about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBen Kimock <kimockb@gmail.com>2025-02-19 05:39:15 +0000
committerGitHub <noreply@github.com>2025-02-19 05:39:15 +0000
commite2ba35a451de25fdad24333040ee3dfca114614b (patch)
tree175f3b6562847b432bc2f26c5a661ff97206c2fa
parent821c33fe073c3e230baa207e88b973f9b4d96072 (diff)
parent2e71770009871a3a8b4ec2974c4918c09445666b (diff)
downloadrust-e2ba35a451de25fdad24333040ee3dfca114614b.tar.gz
rust-e2ba35a451de25fdad24333040ee3dfca114614b.zip
Merge pull request #4197 from rust-lang/rustup-2025-02-19
Automatic Rustup
-rw-r--r--.gitmodules2
-rw-r--r--Cargo.lock219
-rw-r--r--Cargo.toml1
-rw-r--r--RELEASES.md8
-rw-r--r--compiler/rustc_abi/Cargo.toml1
-rw-r--r--compiler/rustc_abi/src/layout.rs9
-rw-r--r--compiler/rustc_abi/src/lib.rs7
-rw-r--r--compiler/rustc_ast/src/ast_traits.rs4
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs2
-rw-r--r--compiler/rustc_ast/src/token.rs30
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs55
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs12
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs5
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs18
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs42
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs20
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs3
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs5
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs1
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/comments.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/global_asm.rs2
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs19
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs12
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mono_item.rs2
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs2
-rw-r--r--compiler/rustc_data_structures/Cargo.toml1
-rw-r--r--compiler/rustc_data_structures/src/fingerprint.rs5
-rw-r--r--compiler/rustc_data_structures/src/intern.rs5
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs3
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/tests.rs3
-rw-r--r--compiler/rustc_driver_impl/src/pretty.rs11
-rw-r--r--compiler/rustc_driver_impl/src/signal_handler.rs50
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0803.md46
-rw-r--r--compiler/rustc_error_codes/src/lib.rs1
-rw-r--r--compiler/rustc_errors/Cargo.toml1
-rw-r--r--compiler/rustc_errors/src/lib.rs3
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs41
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hashes/Cargo.toml9
-rw-r--r--compiler/rustc_hashes/src/lib.rs (renamed from compiler/rustc_data_structures/src/hashes.rs)48
-rw-r--r--compiler/rustc_hir/Cargo.toml1
-rw-r--r--compiler/rustc_hir/src/def_path_hash_map.rs2
-rw-r--r--compiler/rustc_hir/src/definitions.rs3
-rw-r--r--compiler/rustc_hir/src/intravisit.rs88
-rw-r--r--compiler/rustc_hir/src/tests.rs2
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl2
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs100
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs79
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/collect/dump.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs39
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs37
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs154
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/dump.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs2
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs22
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs50
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs12
-rw-r--r--compiler/rustc_incremental/src/assert_dep_graph.rs6
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs6
-rw-r--r--compiler/rustc_interface/messages.ftl4
-rw-r--r--compiler/rustc_interface/src/errors.rs10
-rw-r--r--compiler/rustc_interface/src/lib.rs1
-rw-r--r--compiler/rustc_interface/src/limits.rs (renamed from compiler/rustc_middle/src/middle/limits.rs)59
-rw-r--r--compiler/rustc_interface/src/passes.rs23
-rw-r--r--compiler/rustc_interface/src/proc_macro_decls.rs2
-rw-r--r--compiler/rustc_lint/messages.ftl4
-rw-r--r--compiler/rustc_lint/src/async_closures.rs2
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_lint/src/context.rs4
-rw-r--r--compiler/rustc_lint/src/default_could_be_derived.rs8
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs4
-rw-r--r--compiler/rustc_lint/src/invalid_from_utf8.rs10
-rw-r--r--compiler/rustc_lint/src/late.rs14
-rw-r--r--compiler/rustc_lint/src/levels.rs10
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp20
-rw-r--r--compiler/rustc_metadata/src/foreign_modules.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs11
-rw-r--r--compiler/rustc_middle/Cargo.toml1
-rw-r--r--compiler/rustc_middle/messages.ftl30
-rw-r--r--compiler/rustc_middle/src/error.rs20
-rw-r--r--compiler/rustc_middle/src/hir/map.rs (renamed from compiler/rustc_middle/src/hir/map/mod.rs)271
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs2
-rw-r--r--compiler/rustc_middle/src/hir/nested_filter.rs10
-rw-r--r--compiler/rustc_middle/src/middle/mod.rs5
-rw-r--r--compiler/rustc_middle/src/mir/basic_blocks.rs31
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs65
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs3
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs405
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs32
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs416
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-rw-r--r--compiler/rustc_middle/src/thir.rs1
-rw-r--r--compiler/rustc_middle/src/ty/context.rs12
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs2
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs36
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs5
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs6
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs4
-rw-r--r--compiler/rustc_middle/src/ty/util.rs3
-rw-r--r--compiler/rustc_middle/src/values.rs2
-rw-r--r--compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs1
-rw-r--r--compiler/rustc_mir_build/src/builder/mod.rs7
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs6
-rw-r--r--compiler/rustc_mir_build/src/errors.rs6
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs24
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/migration.rs182
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs134
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs27
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs11
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/initialized.rs13
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs1
-rw-r--r--compiler/rustc_mir_transform/src/check_inline.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs11
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs11
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs6
-rw-r--r--compiler/rustc_mir_transform/src/ffi_unwind_calls.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs2
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs2
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs186
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs8
-rw-r--r--compiler/rustc_mir_transform/src/patch.rs51
-rw-r--r--compiler/rustc_mir_transform/src/single_use_consts.rs8
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/alias_relate.rs12
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs37
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs84
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs22
-rw-r--r--compiler/rustc_parse/src/parser/path.rs16
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs15
-rw-r--r--compiler/rustc_passes/src/check_attr.rs17
-rw-r--r--compiler/rustc_passes/src/dead.rs16
-rw-r--r--compiler/rustc_passes/src/entry.rs2
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs14
-rw-r--r--compiler/rustc_passes/src/input_stats.rs26
-rw-r--r--compiler/rustc_passes/src/lib_features.rs6
-rw-r--r--compiler/rustc_passes/src/liveness.rs7
-rw-r--r--compiler/rustc_passes/src/loops.rs6
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs6
-rw-r--r--compiler/rustc_passes/src/reachable.rs2
-rw-r--r--compiler/rustc_passes/src/stability.rs20
-rw-r--r--compiler/rustc_passes/src/upvars.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs10
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs17
-rw-r--r--compiler/rustc_pattern_analysis/tests/common/mod.rs2
-rw-r--r--compiler/rustc_pattern_analysis/tests/complexity.rs2
-rw-r--r--compiler/rustc_pattern_analysis/tests/exhaustiveness.rs3
-rw-r--r--compiler/rustc_pattern_analysis/tests/intersection.rs3
-rw-r--r--compiler/rustc_privacy/src/lib.rs28
-rw-r--r--compiler/rustc_query_impl/Cargo.toml1
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs3
-rw-r--r--compiler/rustc_query_system/Cargo.toml1
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs2
-rw-r--r--compiler/rustc_resolve/src/imports.rs13
-rw-r--r--compiler/rustc_resolve/src/lib.rs26
-rw-r--r--compiler/rustc_serialize/Cargo.toml1
-rw-r--r--compiler/rustc_serialize/src/serialize.rs29
-rw-r--r--compiler/rustc_session/Cargo.toml1
-rw-r--r--compiler/rustc_session/src/config.rs2
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_session/src/session.rs7
-rw-r--r--compiler/rustc_span/Cargo.toml1
-rw-r--r--compiler/rustc_span/src/def_id.rs5
-rw-r--r--compiler/rustc_span/src/hygiene.rs3
-rw-r--r--compiler/rustc_span/src/lib.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs15
-rw-r--r--compiler/rustc_symbol_mangling/Cargo.toml1
-rw-r--r--compiler/rustc_symbol_mangling/src/hashed.rs3
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs3
-rw-r--r--compiler/rustc_target/src/callconv/mod.rs118
-rw-r--r--compiler/rustc_target/src/callconv/x86.rs14
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i386_apple_ios.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs9
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_linux_android.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/m68k_unknown_none_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/msp430_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32v1_none.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_hurd_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs9
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs9
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs9
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs9
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs10
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs7
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs6
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs16
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs7
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs19
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs44
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs2
-rw-r--r--compiler/rustc_trait_selection/src/errors/note_and_explain.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs2
-rw-r--r--compiler/rustc_ty_utils/Cargo.toml1
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs138
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs4
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs15
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs1
-rw-r--r--config.example.toml7
-rw-r--r--library/alloc/src/borrow.rs12
-rw-r--r--library/core/src/char/methods.rs1
-rw-r--r--library/core/src/iter/adapters/zip.rs8
-rw-r--r--library/core/src/num/int_macros.rs4
-rw-r--r--library/core/src/num/nonzero.rs8
-rw-r--r--library/core/src/num/uint_macros.rs5
-rw-r--r--library/core/src/str/mod.rs20
-rw-r--r--library/core/src/ub_checks.rs6
-rw-r--r--library/std/src/f16.rs2
-rw-r--r--library/std/src/fs.rs102
-rw-r--r--library/std/src/io/stdio.rs1
-rw-r--r--library/std/src/os/wasi/fs.rs11
-rw-r--r--library/std/src/panic.rs1
-rw-r--r--library/std/src/process.rs4
-rw-r--r--library/std/src/sys/pal/hermit/fs.rs4
-rw-r--r--library/std/src/sys/pal/solid/fs.rs5
-rw-r--r--library/std/src/sys/pal/uefi/fs.rs4
-rw-r--r--library/std/src/sys/pal/unix/fs.rs4
-rw-r--r--library/std/src/sys/pal/unsupported/fs.rs4
-rw-r--r--library/std/src/sys/pal/wasi/fs.rs4
-rw-r--r--library/std/src/sys/pal/windows/fs.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs194
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs75
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs23
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs31
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs26
-rw-r--r--src/bootstrap/src/core/build_steps/vendor.rs24
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs3
-rw-r--r--src/bootstrap/src/core/builder/mod.rs41
-rw-r--r--src/bootstrap/src/core/builder/tests.rs4
-rw-r--r--src/bootstrap/src/core/config/config.rs19
-rw-r--r--src/bootstrap/src/core/sanity.rs2
-rw-r--r--src/bootstrap/src/lib.rs28
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/bootstrap/src/utils/proc_macro_deps.rs15
-rw-r--r--src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig2
-rw-r--r--src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig2
-rwxr-xr-xsrc/ci/docker/scripts/rfl-build.sh4
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs2
-rw-r--r--src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md8
-rw-r--r--src/doc/rustc/src/platform-support/loongarch-none.md2
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/clean/inline.rs4
-rw-r--r--src/librustdoc/clean/mod.rs12
-rw-r--r--src/librustdoc/clean/types.rs17
-rw-r--r--src/librustdoc/clean/utils.rs73
-rw-r--r--src/librustdoc/core.rs13
-rw-r--r--src/librustdoc/doctest/make.rs16
-rw-r--r--src/librustdoc/doctest/rust.rs8
-rw-r--r--src/librustdoc/html/render/print_item.rs28
-rw-r--r--src/librustdoc/html/render/span_map.rs14
-rw-r--r--src/librustdoc/json/conversions.rs2
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs2
-rw-r--r--src/librustdoc/scrape_examples.rs9
-rw-r--r--src/librustdoc/visit_ast.rs16
m---------src/llvm-project0
-rw-r--r--src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/utils.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/collection_is_never_read.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/missing_headers.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_drop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/format_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_statements.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_test_module.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytecount.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/format_collect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_filter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/return_and_then.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_canonical_impls.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/single_call_fn.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/string_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unconditional_recursion.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_self.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/zombie_processes.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs8
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs8
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs36
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/mod.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/ptr.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs24
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.stdout4
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_closure.stdout2
-rw-r--r--src/tools/clippy/tests/ui/author/repeat.stdout2
-rw-r--r--src/tools/error_index_generator/Cargo.toml1
-rw-r--r--src/tools/generate-copyright/src/cargo_metadata.rs44
-rw-r--r--src/tools/generate-copyright/src/main.rs50
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr2
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml6
-rw-r--r--src/tools/rust-analyzer/Cargo.lock24
-rw-r--r--src/tools/rust-analyzer/Cargo.toml10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs53
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests.rs45
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs56
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs79
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs38
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs91
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs263
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs168
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs983
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower/diagnostics.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs911
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs50
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs71
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/from_id.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/has_source.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs97
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs136
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs365
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs23
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs91
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs59
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs53
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/annotations.rs67
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs67
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html15
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs27
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs33
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs3
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/lib.rs10
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs174
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs23
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs405
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs16
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs25
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs16
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs173
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs14
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs11
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs30
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs31
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs116
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/panic_context.rs40
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs46
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs3
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs44
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/lib.rs9
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs6
-rw-r--r--src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/lib.rs27
-rw-r--r--src/tools/rust-analyzer/docs/book/README.md2
-rw-r--r--src/tools/rust-analyzer/docs/book/book.toml11
-rw-r--r--src/tools/rust-analyzer/docs/book/src/SUMMARY.md3
-rw-r--r--src/tools/rust-analyzer/docs/book/src/assists_generated.md3820
-rw-r--r--src/tools/rust-analyzer/docs/book/src/configuration_generated.md4
-rw-r--r--src/tools/rust-analyzer/docs/book/src/diagnostics_generated.md516
-rw-r--r--src/tools/rust-analyzer/docs/book/src/features_generated.md940
-rw-r--r--src/tools/rust-analyzer/docs/book/src/installation.md632
-rw-r--r--src/tools/rust-analyzer/docs/book/src/other_editors.md423
-rw-r--r--src/tools/rust-analyzer/docs/book/src/rust_analyzer_binary.md74
-rw-r--r--src/tools/rust-analyzer/docs/book/src/vs_code.md121
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json307
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json6
-rw-r--r--src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md1
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-analyzer/xtask/src/codegen.rs2
-rw-r--r--src/tools/rustbook/Cargo.lock11
-rw-r--r--src/tools/rustbook/Cargo.toml3
-rw-r--r--src/tools/tidy/src/deps.rs3
-rw-r--r--tests/assembly/asm/aarch64-types.rs8
-rw-r--r--tests/assembly/closure-inherit-target-feature.rs7
-rw-r--r--tests/assembly/x86-return-float.rs42
-rw-r--r--tests/auxiliary/minicore.rs22
-rw-r--r--tests/codegen/abi-win64-zst.rs7
-rw-r--r--tests/codegen/abi-x86-sse.rs36
-rw-r--r--tests/codegen/align-byval-alignment-mismatch.rs11
-rw-r--r--tests/codegen/align-byval-vector.rs11
-rw-r--r--tests/codegen/align-byval.rs14
-rw-r--r--tests/codegen/float/f128.rs82
-rw-r--r--tests/codegen/float/f16.rs43
-rw-r--r--tests/codegen/intrinsics/transmute-x64.rs9
-rw-r--r--tests/codegen/issues/issue-32031.rs6
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs17
-rw-r--r--tests/codegen/simd/packed-simd.rs25
-rw-r--r--tests/codegen/union-abi.rs16
-rw-r--r--tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff2
-rw-r--r--tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff2
-rw-r--r--tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff2
-rw-r--r--tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff2
-rw-r--r--tests/run-make/rustc-crates-on-stable/rmake.rs2
-rw-r--r--tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout2
-rw-r--r--tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs4
-rw-r--r--tests/ui-fulldeps/missing-rustc-driver-error.stderr8
-rw-r--r--tests/ui-fulldeps/obtain-borrowck.rs3
-rw-r--r--tests/ui/abi/c-zst.aarch64-darwin.stderr2
-rw-r--r--tests/ui/abi/c-zst.powerpc-linux.stderr2
-rw-r--r--tests/ui/abi/c-zst.rs7
-rw-r--r--tests/ui/abi/c-zst.s390x-linux.stderr2
-rw-r--r--tests/ui/abi/c-zst.sparc64-linux.stderr2
-rw-r--r--tests/ui/abi/c-zst.x86_64-linux.stderr2
-rw-r--r--tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr2
-rw-r--r--tests/ui/associated-consts/issue-93835.rs4
-rw-r--r--tests/ui/associated-consts/issue-93835.stderr37
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr6
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs1
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr6
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr6
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs1
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr18
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr18
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs1
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/nested.rs1
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/simple.rs1
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs1
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs1
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs1
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs1
-rw-r--r--tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr (renamed from tests/ui/feature-gates/feature-gate-pattern-complexity.stderr)8
-rw-r--r--tests/ui/feature-gates/feature-gate-pattern-complexity.rs6
-rw-r--r--tests/ui/generic-associated-types/issue-91883.current.stderr (renamed from tests/ui/generic-associated-types/issue-91883.stderr)6
-rw-r--r--tests/ui/generic-associated-types/issue-91883.next.stderr20
-rw-r--r--tests/ui/generic-associated-types/issue-91883.rs4
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-with-rpit.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs3
-rw-r--r--tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr4
-rw-r--r--tests/ui/issues/issue-20831-debruijn.stderr4
-rw-r--r--tests/ui/layout/debug.rs5
-rw-r--r--tests/ui/layout/debug.stderr8
-rw-r--r--tests/ui/layout/normalization-failure.rs57
-rw-r--r--tests/ui/layout/normalization-failure.stderr12
-rw-r--r--tests/ui/lint/invalid_from_utf8.rs53
-rw-r--r--tests/ui/lint/invalid_from_utf8.stderr237
-rw-r--r--tests/ui/macros/block-to-expr-metavar.rs17
-rw-r--r--tests/ui/macros/macro-interpolation.rs2
-rw-r--r--tests/ui/macros/macro-interpolation.stderr4
-rw-r--r--tests/ui/macros/syntax-error-recovery.rs4
-rw-r--r--tests/ui/macros/syntax-error-recovery.stderr4
-rw-r--r--tests/ui/nll/normalization-bounds-error.stderr4
-rw-r--r--tests/ui/parser/macro/issue-37113.rs2
-rw-r--r--tests/ui/parser/macro/issue-37113.stderr4
-rw-r--r--tests/ui/parser/macro/trait-object-macro-matcher.rs1
-rw-r--r--tests/ui/parser/macro/trait-object-macro-matcher.stderr10
-rw-r--r--tests/ui/parser/raw/raw-idents.rs158
-rw-r--r--tests/ui/pattern/complexity_limit.rs2
-rw-r--r--tests/ui/pattern/usefulness/issue-118437-exponential-time-on-diagonal-match.rs2
-rw-r--r--tests/ui/process/process-sigpipe.rs17
-rw-r--r--tests/ui/regions/regions-normalize-in-where-clause-list.stderr4
-rw-r--r--tests/ui/regions/resolve-re-error-ice.stderr4
-rw-r--r--tests/ui/simd-abi-checks-empty-list.rs9
-rw-r--r--tests/ui/simd-abi-checks-empty-list.stderr4
-rw-r--r--tests/ui/simd-abi-checks-s390x.rs15
-rw-r--r--tests/ui/simd-abi-checks-s390x.z10.stderr62
-rw-r--r--tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr62
-rw-r--r--tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr62
-rw-r--r--tests/ui/sse-simd-abi-checks.rs (renamed from tests/ui/sse-abi-checks.rs)13
-rw-r--r--tests/ui/sse-simd-abi-checks.stderr (renamed from tests/ui/sse-abi-checks.stderr)4
-rw-r--r--tests/ui/static/static-lifetime.stderr4
-rw-r--r--tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.rs6
-rw-r--r--tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.stderr23
-rw-r--r--tests/ui/traits/const-traits/predicate-entailment-passes.rs11
-rw-r--r--tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr4
-rw-r--r--tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr12
-rw-r--r--tests/ui/traits/next-solver/gat-wf.rs16
-rw-r--r--tests/ui/traits/next-solver/gat-wf.stderr15
-rw-r--r--tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr4
953 files changed, 14862 insertions, 6948 deletions
diff --git a/.gitmodules b/.gitmodules
index f9bd42edab3..97a0c0c54cf 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -29,7 +29,7 @@
 [submodule "src/llvm-project"]
 	path = src/llvm-project
 	url = https://github.com/rust-lang/llvm-project.git
-	branch = rustc/19.1-2024-12-03
+	branch = rustc/20.1-2025-02-13
 	shallow = true
 [submodule "src/doc/embedded-book"]
 	path = src/doc/embedded-book
diff --git a/Cargo.lock b/Cargo.lock
index 38a861727a9..22a349b2d32 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -62,19 +62,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
 
 [[package]]
-name = "ammonia"
-version = "4.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459"
-dependencies = [
- "html5ever",
- "maplit",
- "once_cell",
- "tendril",
- "url",
-]
-
-[[package]]
 name = "android-tzdata"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -513,16 +500,6 @@ dependencies = [
  "anstyle",
  "clap_lex",
  "strsim",
- "terminal_size",
-]
-
-[[package]]
-name = "clap_complete"
-version = "4.5.42"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0"
-dependencies = [
- "clap",
 ]
 
 [[package]]
@@ -1085,18 +1062,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
 
 [[package]]
-name = "elasticlunr-rs"
-version = "3.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41e83863a500656dfa214fee6682de9c5b9f03de6860fec531235ed2ae9f6571"
-dependencies = [
- "regex",
- "serde",
- "serde_derive",
- "serde_json",
-]
-
-[[package]]
 name = "elsa"
 version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1160,13 +1125,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "error_index_generator"
-version = "0.0.0"
-dependencies = [
- "mdbook",
-]
-
-[[package]]
 name = "expect-test"
 version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1518,22 +1476,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "handlebars"
-version = "6.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6b224b95c1e668ac0270325ad563b2eef1469fbbb8959bc7c692c844b813d9"
-dependencies = [
- "derive_builder",
- "log",
- "num-order",
- "pest",
- "pest_derive",
- "serde",
- "serde_json",
- "thiserror 2.0.11",
-]
-
-[[package]]
 name = "hashbrown"
 version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2190,12 +2132,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
 
 [[package]]
-name = "maplit"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
-
-[[package]]
 name = "markup5ever"
 version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2229,34 +2165,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "mdbook"
-version = "0.4.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe1f98b8d66e537d2f0ba06e7dec4f44001deec539a2d18bfc102d6a86189148"
-dependencies = [
- "ammonia",
- "anyhow",
- "chrono",
- "clap",
- "clap_complete",
- "elasticlunr-rs",
- "env_logger",
- "handlebars",
- "log",
- "memchr",
- "once_cell",
- "opener",
- "pulldown-cmark 0.10.3",
- "regex",
- "serde",
- "serde_json",
- "shlex",
- "tempfile",
- "toml 0.5.11",
- "topological-sort",
-]
-
-[[package]]
 name = "measureme"
 version = "11.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2303,9 +2211,9 @@ dependencies = [
 
 [[package]]
 name = "minifier"
-version = "0.3.4"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cf47565b1430f5fe6c81d3afcb4b835271348d7eb35294a4d592e38dd09ea22"
+checksum = "9bfdc64e2f805f3d12965f10522000bae36e88d2cfea44112331f467d4f4bf68"
 
 [[package]]
 name = "minimal-lexical"
@@ -2484,21 +2392,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "num-modular"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f"
-
-[[package]]
-name = "num-order"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6"
-dependencies = [
- "num-modular",
-]
-
-[[package]]
 name = "num-rational"
 version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2719,51 +2612,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "pest"
-version = "2.7.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
-dependencies = [
- "memchr",
- "thiserror 2.0.11",
- "ucd-trie",
-]
-
-[[package]]
-name = "pest_derive"
-version = "2.7.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e"
-dependencies = [
- "pest",
- "pest_generator",
-]
-
-[[package]]
-name = "pest_generator"
-version = "2.7.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b"
-dependencies = [
- "pest",
- "pest_meta",
- "proc-macro2",
- "quote",
- "syn 2.0.96",
-]
-
-[[package]]
-name = "pest_meta"
-version = "2.7.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea"
-dependencies = [
- "once_cell",
- "pest",
- "sha2",
-]
-
-[[package]]
 name = "phf"
 version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2923,36 +2771,18 @@ dependencies = [
 
 [[package]]
 name = "pulldown-cmark"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
-dependencies = [
- "bitflags",
- "memchr",
- "pulldown-cmark-escape 0.10.1",
- "unicase",
-]
-
-[[package]]
-name = "pulldown-cmark"
 version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625"
 dependencies = [
  "bitflags",
  "memchr",
- "pulldown-cmark-escape 0.11.0",
+ "pulldown-cmark-escape",
  "unicase",
 ]
 
 [[package]]
 name = "pulldown-cmark-escape"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3"
-
-[[package]]
-name = "pulldown-cmark-escape"
 version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
@@ -3317,6 +3147,7 @@ dependencies = [
  "rand 0.8.5",
  "rand_xoshiro",
  "rustc_data_structures",
+ "rustc_hashes",
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
@@ -3544,6 +3375,7 @@ dependencies = [
  "rustc_errors",
  "rustc_fluent_macro",
  "rustc_fs_util",
+ "rustc_hashes",
  "rustc_hir",
  "rustc_index",
  "rustc_llvm",
@@ -3586,6 +3418,7 @@ dependencies = [
  "rustc_errors",
  "rustc_fluent_macro",
  "rustc_fs_util",
+ "rustc_hashes",
  "rustc_hir",
  "rustc_hir_pretty",
  "rustc_incremental",
@@ -3658,6 +3491,7 @@ dependencies = [
  "rustc-stable-hash",
  "rustc_arena",
  "rustc_graphviz",
+ "rustc_hashes",
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
@@ -3768,6 +3602,7 @@ dependencies = [
  "rustc_error_codes",
  "rustc_error_messages",
  "rustc_fluent_macro",
+ "rustc_hashes",
  "rustc_hir",
  "rustc_index",
  "rustc_lexer",
@@ -3841,6 +3676,13 @@ name = "rustc_graphviz"
 version = "0.0.0"
 
 [[package]]
+name = "rustc_hashes"
+version = "0.0.0"
+dependencies = [
+ "rustc-stable-hash",
+]
+
+[[package]]
 name = "rustc_hir"
 version = "0.0.0"
 dependencies = [
@@ -3849,6 +3691,7 @@ dependencies = [
  "rustc_arena",
  "rustc_ast",
  "rustc_data_structures",
+ "rustc_hashes",
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
@@ -4169,6 +4012,7 @@ dependencies = [
  "rustc_feature",
  "rustc_fluent_macro",
  "rustc_graphviz",
+ "rustc_hashes",
  "rustc_hir",
  "rustc_hir_pretty",
  "rustc_index",
@@ -4405,6 +4249,7 @@ dependencies = [
  "measureme",
  "rustc_data_structures",
  "rustc_errors",
+ "rustc_hashes",
  "rustc_hir",
  "rustc_index",
  "rustc_middle",
@@ -4428,6 +4273,7 @@ dependencies = [
  "rustc_errors",
  "rustc_feature",
  "rustc_fluent_macro",
+ "rustc_hashes",
  "rustc_hir",
  "rustc_index",
  "rustc_macros",
@@ -4488,6 +4334,7 @@ name = "rustc_serialize"
 version = "0.0.0"
 dependencies = [
  "indexmap",
+ "rustc_hashes",
  "rustc_macros",
  "smallvec",
  "tempfile",
@@ -4508,6 +4355,7 @@ dependencies = [
  "rustc_feature",
  "rustc_fluent_macro",
  "rustc_fs_util",
+ "rustc_hashes",
  "rustc_hir",
  "rustc_lint_defs",
  "rustc_macros",
@@ -4549,6 +4397,7 @@ dependencies = [
  "md-5",
  "rustc_arena",
  "rustc_data_structures",
+ "rustc_hashes",
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
@@ -4568,6 +4417,7 @@ dependencies = [
  "rustc_abi",
  "rustc_data_structures",
  "rustc_errors",
+ "rustc_hashes",
  "rustc_hir",
  "rustc_middle",
  "rustc_session",
@@ -4663,6 +4513,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fluent_macro",
+ "rustc_hashes",
  "rustc_hir",
  "rustc_index",
  "rustc_infer",
@@ -5290,16 +5141,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "terminal_size"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9"
-dependencies = [
- "rustix",
- "windows-sys 0.59.0",
-]
-
-[[package]]
 name = "termize"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5540,12 +5381,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "topological-sort"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
-
-[[package]]
 name = "tracing"
 version = "0.1.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5666,12 +5501,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "ucd-trie"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
-
-[[package]]
 name = "ui_test"
 version = "0.26.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 97e782d0df0..20a43aaaeeb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,6 @@ members = [
   "src/tools/clippy/clippy_dev",
   "src/tools/compiletest",
   "src/tools/run-make-support",
-  "src/tools/error_index_generator",
   "src/tools/linkchecker",
   "src/tools/lint-docs",
   "src/tools/miropt-test-tools",
diff --git a/RELEASES.md b/RELEASES.md
index f0def1a0e42..038d7ca639f 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -34,7 +34,8 @@ Libraries
 ---------
 - [Panics in the standard library now have a leading `library/` in their path](https://github.com/rust-lang/rust/pull/132390)
 - [`std::env::home_dir()` on Windows now ignores the non-standard `$HOME` environment variable](https://github.com/rust-lang/rust/pull/132515)
-   It will be un-deprecated in a subsequent release.
+
+  It will be un-deprecated in a subsequent release.
 - [Add `AsyncFn*` to the prelude in all editions.](https://github.com/rust-lang/rust/pull/132611)
 
 <a id="1.85.0-Stabilized-APIs"></a>
@@ -98,15 +99,18 @@ Rustdoc
 Compatibility Notes
 -------------------
 - [`rustc` no longer treats the `test` cfg as a well known check-cfg](https://github.com/rust-lang/rust/pull/131729), instead it is up to the build systems and users of `--check-cfg`[^check-cfg] to set it as a well known cfg using `--check-cfg=cfg(test)`.
+
   This is done to enable build systems like Cargo to set it conditionally, as not all source files are suitable for unit tests.
   [Cargo (for now) unconditionally sets the `test` cfg as a well known cfg](https://github.com/rust-lang/cargo/pull/14963).
-[^check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html
+  [^check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html
 - [Disable potentially incorrect type inference if there are trivial and non-trivial where-clauses](https://github.com/rust-lang/rust/pull/132325)
 - `std::env::home_dir()` has been deprecated for years, because it can give surprising results in some Windows configurations if the `HOME` environment variable is set (which is not the normal configuration on Windows). We had previously avoided changing its behavior, out of concern for compatibility with code depending on this non-standard configuration. Given how long this function has been deprecated, we're now fixing its behavior as a bugfix. A subsequent release will remove the deprecation for this function.
 - [Make `core::ffi::c_char` signedness more closely match that of the platform-default `char`](https://github.com/rust-lang/rust/pull/132975)
+
   This changed `c_char` from an `i8` to `u8` or vice versa on many Tier 2 and 3
   targets (mostly Arm and RISC-V embedded targets). The new definition may
   result in compilation failures but fixes compatibility issues with C.
+
   The `libc` crate matches this change as of its 0.2.169 release.
 - [When compiling a nested `macro_rules` macro from an external crate, the content of the inner `macro_rules` is now built with the edition of the external crate, not the local crate.](https://github.com/rust-lang/rust/pull/133274)
 - [Increase `sparcv9-sun-solaris` and `x86_64-pc-solaris` Solaris baseline to 11.4.](https://github.com/rust-lang/rust/pull/133293)
diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml
index 1013f1d3958..3d6f4a6a109 100644
--- a/compiler/rustc_abi/Cargo.toml
+++ b/compiler/rustc_abi/Cargo.toml
@@ -9,6 +9,7 @@ bitflags = "2.4.1"
 rand = { version = "0.8.4", default-features = false, optional = true }
 rand_xoshiro = { version = "0.6.0", optional = true }
 rustc_data_structures = { path = "../rustc_data_structures", optional = true  }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_index = { path = "../rustc_index", default-features = false }
 rustc_macros = { path = "../rustc_macros", optional = true }
 rustc_serialize = { path = "../rustc_serialize", optional = true  }
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index b8773f9ff38..45cd0b517f6 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -2,6 +2,7 @@ use std::fmt::{self, Write};
 use std::ops::{Bound, Deref};
 use std::{cmp, iter};
 
+use rustc_hashes::Hash64;
 use rustc_index::Idx;
 use tracing::debug;
 
@@ -133,7 +134,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             size,
             max_repr_align: None,
             unadjusted_abi_align: align.abi,
-            randomization_seed: combined_seed,
+            randomization_seed: Hash64::new(combined_seed),
         }
     }
 
@@ -226,7 +227,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             size: Size::ZERO,
             max_repr_align: None,
             unadjusted_abi_align: dl.i8_align.abi,
-            randomization_seed: 0,
+            randomization_seed: Hash64::ZERO,
         }
     }
 
@@ -1058,7 +1059,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         // unsizable tail fields are excluded so that we use the same seed for the sized and unsized layouts.
         let field_seed = fields_excluding_tail
             .iter()
-            .fold(0u64, |acc, f| acc.wrapping_add(f.randomization_seed));
+            .fold(Hash64::ZERO, |acc, f| acc.wrapping_add(f.randomization_seed));
 
         if optimize_field_order && fields.len() > 1 {
             // If `-Z randomize-layout` was enabled for the type definition we can shuffle
@@ -1072,7 +1073,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
                     // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field
                     // ordering.
                     let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64(
-                        field_seed.wrapping_add(repr.field_shuffle_seed),
+                        field_seed.wrapping_add(repr.field_shuffle_seed).as_u64(),
                     );
 
                     // Shuffle the ordering of the fields.
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index da1c706d67c..dbb4bed5cdd 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -50,6 +50,7 @@ use std::str::FromStr;
 use bitflags::bitflags;
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::StableOrd;
+use rustc_hashes::Hash64;
 use rustc_index::{Idx, IndexSlice, IndexVec};
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_Generic, Encodable_Generic, HashStable_Generic};
@@ -140,7 +141,7 @@ pub struct ReprOptions {
     /// hash without loss, but it does pay the price of being larger.
     /// Everything's a tradeoff, a 64-bit seed should be sufficient for our
     /// purposes (primarily `-Z randomize-layout`)
-    pub field_shuffle_seed: u64,
+    pub field_shuffle_seed: Hash64,
 }
 
 impl ReprOptions {
@@ -1727,7 +1728,7 @@ pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> {
     /// transmuted to `Foo<U>` we aim to create probalistically distinct seeds so that Foo can choose
     /// to reorder its fields based on that information. The current implementation is a conservative
     /// approximation of this goal.
-    pub randomization_seed: u64,
+    pub randomization_seed: Hash64,
 }
 
 impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
@@ -1781,7 +1782,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
             align,
             max_repr_align: None,
             unadjusted_abi_align: align.abi,
-            randomization_seed,
+            randomization_seed: Hash64::new(randomization_seed),
         }
     }
 }
diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index 60f8c6e1048..346edc87c86 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -203,10 +203,8 @@ impl HasTokens for Nonterminal {
             Nonterminal::NtStmt(stmt) => stmt.tokens(),
             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(),
             Nonterminal::NtPat(pat) => pat.tokens(),
-            Nonterminal::NtTy(ty) => ty.tokens(),
             Nonterminal::NtMeta(attr_item) => attr_item.tokens(),
             Nonterminal::NtPath(path) => path.tokens(),
-            Nonterminal::NtVis(vis) => vis.tokens(),
             Nonterminal::NtBlock(block) => block.tokens(),
         }
     }
@@ -216,10 +214,8 @@ impl HasTokens for Nonterminal {
             Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
             Nonterminal::NtPat(pat) => pat.tokens_mut(),
-            Nonterminal::NtTy(ty) => ty.tokens_mut(),
             Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
             Nonterminal::NtPath(path) => path.tokens_mut(),
-            Nonterminal::NtVis(vis) => vis.tokens_mut(),
             Nonterminal::NtBlock(block) => block.tokens_mut(),
         }
     }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index de9f049704a..40b29fdba25 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -907,7 +907,6 @@ fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
         }),
         token::NtPat(pat) => vis.visit_pat(pat),
         token::NtExpr(expr) => vis.visit_expr(expr),
-        token::NtTy(ty) => vis.visit_ty(ty),
         token::NtLiteral(expr) => vis.visit_expr(expr),
         token::NtMeta(item) => {
             let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();
@@ -916,7 +915,6 @@ fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
             visit_lazy_tts(vis, tokens);
         }
         token::NtPath(path) => vis.visit_path(path),
-        token::NtVis(visib) => vis.visit_vis(visib),
     }
 }
 
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 36a7b7d8789..97d121909f8 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -84,7 +84,9 @@ pub enum MetaVarKind {
         // This field is needed for `Token::can_begin_string_literal`.
         can_begin_string_literal: bool,
     },
-    Ty,
+    Ty {
+        is_path: bool,
+    },
     Ident,
     Lifetime,
     Literal,
@@ -104,7 +106,7 @@ impl fmt::Display for MetaVarKind {
             MetaVarKind::Pat(PatParam { inferred: false }) => sym::pat_param,
             MetaVarKind::Expr { kind: Expr2021 { inferred: true } | Expr, .. } => sym::expr,
             MetaVarKind::Expr { kind: Expr2021 { inferred: false }, .. } => sym::expr_2021,
-            MetaVarKind::Ty => sym::ty,
+            MetaVarKind::Ty { .. } => sym::ty,
             MetaVarKind::Ident => sym::ident,
             MetaVarKind::Lifetime => sym::lifetime,
             MetaVarKind::Literal => sym::literal,
@@ -659,7 +661,6 @@ impl Token {
                     | NtMeta(..)
                     | NtPat(..)
                     | NtPath(..)
-                    | NtTy(..)
                 ),
             OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
                 MetaVarKind::Expr { .. } |
@@ -667,7 +668,7 @@ impl Token {
                 MetaVarKind::Meta |
                 MetaVarKind::Pat(_) |
                 MetaVarKind::Path |
-                MetaVarKind::Ty
+                MetaVarKind::Ty { .. }
             ))) => true,
             _ => false,
         }
@@ -688,9 +689,9 @@ impl Token {
             Lifetime(..)                | // lifetime bound in trait object
             Lt | BinOp(Shl)             | // associated path
             PathSep                      => true, // global path
-            Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
+            Interpolated(ref nt) => matches!(&**nt, NtPath(..)),
             OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
-                MetaVarKind::Ty |
+                MetaVarKind::Ty { .. } |
                 MetaVarKind::Path
             ))) => true,
             // For anonymous structs or unions, which only appear in specific positions
@@ -969,6 +970,15 @@ impl Token {
         }
     }
 
+    /// Is this an invisible open delimiter at the start of a token sequence
+    /// from an expanded metavar?
+    pub fn is_metavar_seq(&self) -> Option<MetaVarKind> {
+        match self.kind {
+            OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => Some(kind),
+            _ => None,
+        }
+    }
+
     pub fn glue(&self, joint: &Token) -> Option<Token> {
         let kind = match self.kind {
             Eq => match joint.kind {
@@ -1067,12 +1077,10 @@ pub enum Nonterminal {
     NtStmt(P<ast::Stmt>),
     NtPat(P<ast::Pat>),
     NtExpr(P<ast::Expr>),
-    NtTy(P<ast::Ty>),
     NtLiteral(P<ast::Expr>),
     /// Stuff inside brackets for attributes
     NtMeta(P<ast::AttrItem>),
     NtPath(P<ast::Path>),
-    NtVis(P<ast::Visibility>),
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
@@ -1166,10 +1174,8 @@ impl Nonterminal {
             NtStmt(stmt) => stmt.span,
             NtPat(pat) => pat.span,
             NtExpr(expr) | NtLiteral(expr) => expr.span,
-            NtTy(ty) => ty.span,
             NtMeta(attr_item) => attr_item.span(),
             NtPath(path) => path.span,
-            NtVis(vis) => vis.span,
         }
     }
 
@@ -1181,10 +1187,8 @@ impl Nonterminal {
             NtPat(..) => "pattern",
             NtExpr(..) => "expression",
             NtLiteral(..) => "literal",
-            NtTy(..) => "type",
             NtMeta(..) => "attribute",
             NtPath(..) => "path",
-            NtVis(..) => "visibility",
         }
     }
 }
@@ -1207,11 +1211,9 @@ impl fmt::Debug for Nonterminal {
             NtStmt(..) => f.pad("NtStmt(..)"),
             NtPat(..) => f.pad("NtPat(..)"),
             NtExpr(..) => f.pad("NtExpr(..)"),
-            NtTy(..) => f.pad("NtTy(..)"),
             NtLiteral(..) => f.pad("NtLiteral(..)"),
             NtMeta(..) => f.pad("NtMeta(..)"),
             NtPath(..) => f.pad("NtPath(..)"),
-            NtVis(..) => f.pad("NtVis(..)"),
         }
     }
 }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 50f10d083a0..1123ea3a449 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -469,10 +469,8 @@ impl TokenStream {
             }
             Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt),
             Nonterminal::NtPat(pat) => TokenStream::from_ast(pat),
-            Nonterminal::NtTy(ty) => TokenStream::from_ast(ty),
             Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr),
             Nonterminal::NtPath(path) => TokenStream::from_ast(path),
-            Nonterminal::NtVis(vis) => TokenStream::from_ast(vis),
             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr),
         }
     }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index facc9414b20..1c777111896 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -407,7 +407,7 @@ fn compute_hir_hash(
         .iter_enumerated()
         .filter_map(|(def_id, info)| {
             let info = info.as_owner()?;
-            let def_path_hash = tcx.hir().def_path_hash(def_id);
+            let def_path_hash = tcx.hir_def_path_hash(def_id);
             Some((def_path_hash, info))
         })
         .collect();
@@ -497,7 +497,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             "adding a def'n for node-id {:?} and def kind {:?} but a previous def'n exists: {:?}",
             node_id,
             def_kind,
-            self.tcx.hir().def_key(self.local_def_id(node_id)),
+            self.tcx.hir_def_key(self.local_def_id(node_id)),
         );
 
         let def_id = self.tcx.at(span).create_def(parent, name, def_kind).def_id();
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 6269728e67f..b2cc58fbe11 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -14,16 +14,15 @@ use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, MultiSpan, struct_span_code_err};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit::{Map, Visitor, walk_block, walk_expr};
+use rustc_hir::intravisit::{Visitor, walk_block, walk_expr};
 use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter::OnlyBodies;
-use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::{
     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
     FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
-    Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
-    TerminatorKind, VarBindingForm, VarDebugInfoContents,
+    Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement, StatementKind,
+    Terminator, TerminatorKind, VarBindingForm, VarDebugInfoContents,
 };
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{
@@ -348,13 +347,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             expr: Option<&'hir hir::Expr<'hir>>,
             pat: Option<&'hir hir::Pat<'hir>>,
             parent_pat: Option<&'hir hir::Pat<'hir>>,
-            hir: rustc_middle::hir::map::Map<'hir>,
+            tcx: TyCtxt<'hir>,
         }
         impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
             type NestedFilter = OnlyBodies;
 
-            fn nested_visit_map(&mut self) -> Self::Map {
-                self.hir
+            fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+                self.tcx
             }
 
             fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
@@ -386,8 +385,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 hir::intravisit::walk_pat(self, p);
             }
         }
+        let tcx = self.infcx.tcx;
         let hir = self.infcx.tcx.hir();
-        if let Some(body) = hir.maybe_body_owned_by(self.mir_def_id()) {
+        if let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) {
             let expr = body.value;
             let place = &self.move_data.move_paths[mpi].place;
             let span = place.as_local().map(|local| self.body.local_decls[local].source_info.span);
@@ -396,7 +396,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 expr: None,
                 pat: None,
                 parent_pat: None,
-                hir,
+                tcx,
             };
             finder.visit_expr(expr);
             if let Some(span) = span
@@ -782,9 +782,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
         // We use the statements were the binding was initialized, and inspect the HIR to look
         // for the branching codepaths that aren't covered, to point at them.
-        let map = self.infcx.tcx.hir();
-        let body = map.body_owned_by(self.mir_def_id());
-        let mut visitor = ConditionVisitor { tcx: self.infcx.tcx, spans, name, errors: vec![] };
+        let tcx = self.infcx.tcx;
+        let body = tcx.hir_body_owned_by(self.mir_def_id());
+        let mut visitor = ConditionVisitor { tcx, spans, name, errors: vec![] };
         visitor.visit_body(&body);
         let spans = visitor.spans;
 
@@ -1082,7 +1082,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 ] {
                     for (destination, sp) in elements {
                         if let Ok(hir_id) = destination.target_id
-                            && let hir::Node::Expr(expr) = tcx.hir().hir_node(hir_id)
+                            && let hir::Node::Expr(expr) = tcx.hir_node(hir_id)
                             && !matches!(
                                 sp.desugaring_kind(),
                                 Some(DesugaringKind::ForLoop | DesugaringKind::WhileLoop)
@@ -1437,7 +1437,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         let Some(hir_generics) = tcx
             .typeck_root_def_id(self.mir_def_id().to_def_id())
             .as_local()
-            .and_then(|def_id| tcx.hir().get_generics(def_id))
+            .and_then(|def_id| tcx.hir_get_generics(def_id))
         else {
             return;
         };
@@ -1889,7 +1889,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
     fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'infcx>, place: Place<'tcx>) {
         let tcx = self.infcx.tcx;
-        let hir = tcx.hir();
         let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
 
         struct FindUselessClone<'tcx> {
@@ -1917,7 +1916,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
         let mut expr_finder = FindUselessClone::new(tcx, self.mir_def_id());
 
-        let body = hir.body(body_id).value;
+        let body = tcx.hir_body(body_id).value;
         expr_finder.visit_expr(body);
 
         struct Holds<'tcx> {
@@ -2106,7 +2105,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         let tcx = self.infcx.tcx;
         let body_id = tcx.hir_node(self.mir_hir_id()).body_id()?;
         let mut expr_finder = FindExprBySpan::new(span, tcx);
-        expr_finder.visit_expr(tcx.hir().body(body_id).value);
+        expr_finder.visit_expr(tcx.hir_body(body_id).value);
         expr_finder.result
     }
 
@@ -2258,7 +2257,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
     ) {
         let issue_span = issued_spans.args_or_use();
         let tcx = self.infcx.tcx;
-        let hir = tcx.hir();
 
         let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
         let typeck_results = tcx.typeck(self.mir_def_id());
@@ -2346,7 +2344,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             pat_span: None,
             head: None,
         };
-        finder.visit_expr(hir.body(body_id).value);
+        finder.visit_expr(tcx.hir_body(body_id).value);
 
         if let Some(body_expr) = finder.body_expr
             && let Some(loop_span) = finder.loop_span
@@ -2445,7 +2443,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
     ) {
         let &UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
         let tcx = self.infcx.tcx;
-        let hir = tcx.hir();
 
         // Get the type of the local that we are trying to borrow
         let local = borrowed_place.local;
@@ -2454,10 +2451,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         // Get the body the error happens in
         let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
 
-        let body_expr = hir.body(body_id).value;
+        let body_expr = tcx.hir_body(body_id).value;
 
         struct ClosureFinder<'hir> {
-            hir: rustc_middle::hir::map::Map<'hir>,
+            tcx: TyCtxt<'hir>,
             borrow_span: Span,
             res: Option<(&'hir hir::Expr<'hir>, &'hir hir::Closure<'hir>)>,
             /// The path expression with the `borrow_span` span
@@ -2466,8 +2463,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         impl<'hir> Visitor<'hir> for ClosureFinder<'hir> {
             type NestedFilter = OnlyBodies;
 
-            fn nested_visit_map(&mut self) -> Self::Map {
-                self.hir
+            fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+                self.tcx
             }
 
             fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
@@ -2493,7 +2490,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
         // Find the closure that most tightly wraps `capture_kind_span`
         let mut finder =
-            ClosureFinder { hir, borrow_span: capture_kind_span, res: None, error_path: None };
+            ClosureFinder { tcx, borrow_span: capture_kind_span, res: None, error_path: None };
         finder.visit_expr(body_expr);
         let Some((closure_expr, closure)) = finder.res else { return };
 
@@ -2524,7 +2521,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
         // Find the first argument with a matching type, get its name
         let Some((_, this_name)) =
-            params.iter().zip(hir.body_param_names(closure.body)).find(|(param_ty, name)| {
+            params.iter().zip(tcx.hir_body_param_names(closure.body)).find(|(param_ty, name)| {
                 // FIXME: also support deref for stuff like `Rc` arguments
                 param_ty.peel_refs() == local_ty && name != &Ident::empty()
             })
@@ -2558,7 +2555,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             }
 
             let mut finder = VariableUseFinder { local_id, spans: Vec::new() };
-            finder.visit_expr(hir.body(closure.body).value);
+            finder.visit_expr(tcx.hir_body(closure.body).value);
 
             spans = finder.spans;
         } else {
@@ -3211,7 +3208,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 if let Some(scope) = self.body.source_scopes.get(source_info.scope)
                     && let ClearCrossCrate::Set(scope_data) = &scope.local_data
                     && let Some(id) = self.infcx.tcx.hir_node(scope_data.lint_root).body_id()
-                    && let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind
+                    && let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir_body(id).value.kind
                 {
                     for stmt in block.stmts {
                         let mut visitor = NestedStatementVisitor {
@@ -4180,7 +4177,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
         let is_closure = self.infcx.tcx.is_closure_like(did.to_def_id());
         let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did);
-        let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
+        let fn_decl = self.infcx.tcx.hir_fn_decl_by_hir_id(fn_hir_id)?;
 
         // We need to work out which arguments to highlight. We do this by looking
         // at the return type, where there are three cases:
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 3e474225afd..a88b27f2476 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -75,10 +75,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
 
         if let Some(span) = borrow_span {
             let def_id = body.source.def_id();
-            if let Some(node) = tcx.hir().get_if_local(def_id)
+            if let Some(node) = tcx.hir_get_if_local(def_id)
                 && let Some(body_id) = node.body_id()
             {
-                let body = tcx.hir().body(body_id);
+                let body = tcx.hir_body(body_id);
                 let mut expr_finder = FindExprBySpan::new(span, tcx);
                 expr_finder.visit_expr(body.value);
                 if let Some(mut expr) = expr_finder.result {
@@ -256,8 +256,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
 
                         impl<'hir> rustc_hir::intravisit::Visitor<'hir> for FindLetExpr<'hir> {
                             type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
-                            fn nested_visit_map(&mut self) -> Self::Map {
-                                self.tcx.hir()
+                            fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+                                self.tcx
                             }
                             fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
                                 if let hir::ExprKind::If(cond, _conseq, _alt)
@@ -308,9 +308,9 @@ impl<'tcx> BorrowExplanation<'tcx> {
                             suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
                         } else if let Some((old, new)) = multiple_borrow_span
                             && let def_id = body.source.def_id()
-                            && let Some(node) = tcx.hir().get_if_local(def_id)
+                            && let Some(node) = tcx.hir_get_if_local(def_id)
                             && let Some(body_id) = node.body_id()
-                            && let hir_body = tcx.hir().body(body_id)
+                            && let hir_body = tcx.hir_body(body_id)
                             && let mut expr_finder = (FindLetExpr { span: old, result: None, tcx })
                             && let Some((let_expr_span, let_expr_pat, let_expr_init)) = {
                                 expr_finder.visit_expr(hir_body.value);
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index df83ac985c6..7da089c5e8c 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -13,10 +13,9 @@ use rustc_infer::infer::{
 };
 use rustc_infer::traits::SelectionError;
 use rustc_middle::bug;
-use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::{
     AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,
-    LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement,
+    LocalKind, Location, Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement,
     StatementKind, Terminator, TerminatorKind, find_self_call,
 };
 use rustc_middle::ty::print::Print;
@@ -1220,7 +1219,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                             .tcx
                             .typeck_root_def_id(self.mir_def_id().to_def_id())
                             .as_local()
-                            .and_then(|def_id| self.infcx.tcx.hir().get_generics(def_id))
+                            .and_then(|def_id| self.infcx.tcx.hir_get_generics(def_id))
                         && let spans = hir_generics
                             .predicates
                             .iter()
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 58c5c2fd774..ddf6187a662 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -7,7 +7,7 @@ use rustc_hir::intravisit::Visitor;
 use rustc_hir::{self as hir, CaptureBy, ExprKind, HirId, Node};
 use rustc_middle::bug;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
 use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
 use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
@@ -347,7 +347,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         // Find the closure that captured the binding.
         let mut expr_finder = FindExprBySpan::new(args_span, tcx);
         expr_finder.include_closures = true;
-        expr_finder.visit_expr(tcx.hir().body(body_id).value);
+        expr_finder.visit_expr(tcx.hir_body(body_id).value);
         let Some(closure_expr) = expr_finder.result else { return };
         let ExprKind::Closure(closure) = closure_expr.kind else { return };
         // We'll only suggest cloning the binding if it's a `move` closure.
@@ -357,7 +357,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         let use_span = use_spans.var_or_use();
         let mut expr_finder = FindExprBySpan::new(use_span, tcx);
         expr_finder.include_closures = true;
-        expr_finder.visit_expr(tcx.hir().body(body_id).value);
+        expr_finder.visit_expr(tcx.hir_body(body_id).value);
         let Some(use_expr) = expr_finder.result else { return };
         let parent = tcx.parent_hir_node(use_expr.hir_id);
         if let Node::Expr(expr) = parent
@@ -690,7 +690,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         /// make it bind by reference instead (if possible)
         struct BindingFinder<'tcx> {
             typeck_results: &'tcx ty::TypeckResults<'tcx>,
-            hir: rustc_middle::hir::map::Map<'tcx>,
+            tcx: TyCtxt<'tcx>,
             /// Input: the span of the pattern we're finding bindings in
             pat_span: Span,
             /// Input: the spans of the bindings we're providing suggestions for
@@ -709,8 +709,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         impl<'tcx> Visitor<'tcx> for BindingFinder<'tcx> {
             type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
 
-            fn nested_visit_map(&mut self) -> Self::Map {
-                self.hir
+            fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+                self.tcx
             }
 
             fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {
@@ -777,12 +777,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         }
         let Some(pat_span) = pat_span else { return };
 
-        let hir = self.infcx.tcx.hir();
-        let Some(body) = hir.maybe_body_owned_by(self.mir_def_id()) else { return };
+        let tcx = self.infcx.tcx;
+        let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) else { return };
         let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
         let mut finder = BindingFinder {
             typeck_results,
-            hir,
+            tcx,
             pat_span,
             binding_spans,
             found_pat: false,
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 706dd7135f7..be83e61f75d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -648,10 +648,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     }
                 }
             }
-            let hir_map = self.infcx.tcx.hir();
             let def_id = self.body.source.def_id();
             let Some(local_def_id) = def_id.as_local() else { return };
-            let Some(body) = hir_map.maybe_body_owned_by(local_def_id) else { return };
+            let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id) else { return };
 
             let mut v = SuggestIndexOperatorAlternativeVisitor {
                 assign_span: span,
@@ -749,7 +748,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         // `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)`
         let def_id = self.body.source.def_id();
         if let Some(local_def_id) = def_id.as_local()
-            && let Some(body) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
+            && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id)
             && let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(&body).break_value()
             && let node = self.infcx.tcx.hir_node(hir_id)
             && let hir::Node::LetStmt(hir::LetStmt {
@@ -856,7 +855,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         use hir::ExprKind::{AddrOf, Block, Call, MethodCall};
         use hir::{BorrowKind, Expr};
 
-        let hir_map = self.infcx.tcx.hir();
+        let tcx = self.infcx.tcx;
         struct Finder {
             span: Span,
         }
@@ -871,7 +870,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 }
             }
         }
-        if let Some(body) = hir_map.maybe_body_owned_by(self.mir_def_id())
+        if let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id())
             && let Block(block, _) = body.value.kind
         {
             // `span` corresponds to the expression being iterated, find the `for`-loop desugared
@@ -884,17 +883,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     MethodCall(path_segment, _, _, span) => {
                         // We have `for _ in iter.read_only_iter()`, try to
                         // suggest `for _ in iter.mutable_iter()` instead.
-                        let opt_suggestions = self
-                            .infcx
-                            .tcx
+                        let opt_suggestions = tcx
                             .typeck(path_segment.hir_id.owner.def_id)
                             .type_dependent_def_id(expr.hir_id)
-                            .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
-                            .map(|def_id| self.infcx.tcx.associated_items(def_id))
+                            .and_then(|def_id| tcx.impl_of_method(def_id))
+                            .map(|def_id| tcx.associated_items(def_id))
                             .map(|assoc_items| {
                                 assoc_items
                                     .in_definition_order()
-                                    .map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx))
+                                    .map(|assoc_item_def| assoc_item_def.ident(tcx))
                                     .filter(|&ident| {
                                         let original_method_ident = path_segment.ident;
                                         original_method_ident != ident
@@ -936,12 +933,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
     fn expected_fn_found_fn_mut_call(&self, err: &mut Diag<'_>, sp: Span, act: &str) {
         err.span_label(sp, format!("cannot {act}"));
 
-        let hir = self.infcx.tcx.hir();
+        let tcx = self.infcx.tcx;
+        let hir = tcx.hir();
         let closure_id = self.mir_hir_id();
-        let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
-        let fn_call_id = self.infcx.tcx.parent_hir_id(closure_id);
-        let node = self.infcx.tcx.hir_node(fn_call_id);
-        let def_id = hir.enclosing_body_owner(fn_call_id);
+        let closure_span = tcx.def_span(self.mir_def_id());
+        let fn_call_id = tcx.parent_hir_id(closure_id);
+        let node = tcx.hir_node(fn_call_id);
+        let def_id = tcx.hir_enclosing_body_owner(fn_call_id);
         let mut look_at_return = true;
 
         // If the HIR node is a function or method call gets the def ID
@@ -951,7 +949,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 return None;
             };
 
-            let typeck_results = self.infcx.tcx.typeck(def_id);
+            let typeck_results = tcx.typeck(def_id);
 
             match kind {
                 hir::ExprKind::Call(expr, args) => {
@@ -980,7 +978,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 .map(|(pos, _)| pos)
                 .next();
 
-            let arg = match hir.get_if_local(callee_def_id) {
+            let arg = match tcx.hir_get_if_local(callee_def_id) {
                 Some(
                     hir::Node::Item(hir::Item {
                         ident, kind: hir::ItemKind::Fn { sig, .. }, ..
@@ -1022,7 +1020,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         if look_at_return && hir.get_fn_id_for_return_block(closure_id).is_some() {
             // ...otherwise we are probably in the tail expression of the function, point at the
             // return type.
-            match self.infcx.tcx.hir_node_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
+            match tcx.hir_node_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
                 hir::Node::Item(hir::Item {
                     ident, kind: hir::ItemKind::Fn { sig, .. }, ..
                 })
@@ -1050,9 +1048,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
     fn suggest_using_iter_mut(&self, err: &mut Diag<'_>) {
         let source = self.body.source;
-        let hir = self.infcx.tcx.hir();
         if let InstanceKind::Item(def_id) = source.instance
-            && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
+            && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) =
+                self.infcx.tcx.hir_get_if_local(def_id)
             && let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
             && let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id)
         {
@@ -1274,7 +1272,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             }) => {
                 let def_id = self.body.source.def_id();
                 let hir_id = if let Some(local_def_id) = def_id.as_local()
-                    && let Some(body) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
+                    && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id)
                 {
                     BindingFinder { span: err_label_span }.visit_body(&body).break_value()
                 } else {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index df79da76bce..55b6367f35f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -219,7 +219,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         lower_bound: RegionVid,
     ) {
         let mut suggestions = vec![];
-        let hir = self.infcx.tcx.hir();
+        let tcx = self.infcx.tcx;
 
         // find generic associated types in the given region 'lower_bound'
         let gat_id_and_generics = self
@@ -228,12 +228,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             .map(|placeholder| {
                 if let Some(id) = placeholder.bound.kind.get_id()
                     && let Some(placeholder_id) = id.as_local()
-                    && let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id)
-                    && let Some(generics_impl) = self
-                        .infcx
-                        .tcx
-                        .parent_hir_node(self.infcx.tcx.parent_hir_id(gat_hir_id))
-                        .generics()
+                    && let gat_hir_id = tcx.local_def_id_to_hir_id(placeholder_id)
+                    && let Some(generics_impl) =
+                        tcx.parent_hir_node(tcx.parent_hir_id(gat_hir_id)).generics()
                 {
                     Some((gat_hir_id, generics_impl))
                 } else {
@@ -254,7 +251,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 };
                 if bound_generic_params
                     .iter()
-                    .rfind(|bgp| self.infcx.tcx.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id)
+                    .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id)
                     .is_some()
                 {
                     for bound in *bounds {
@@ -270,7 +267,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 return;
             };
             diag.span_note(*trait_span, fluent::borrowck_limitations_implies_static);
-            let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local())
+            let Some(generics_fn) = tcx.hir_get_generics(self.body.source.def_id().expect_local())
             else {
                 return;
             };
@@ -1162,7 +1159,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
         if ocx.select_all_or_error().is_empty() && count > 0 {
             diag.span_suggestion_verbose(
-                tcx.hir().body(*body).value.peel_blocks().span.shrink_to_lo(),
+                tcx.hir_body(*body).value.peel_blocks().span.shrink_to_lo(),
                 fluent::borrowck_dereference_suggestion,
                 "*".repeat(count),
                 Applicability::MachineApplicable,
@@ -1172,8 +1169,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
     #[allow(rustc::diagnostic_outside_of_impl)]
     fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
-        let map = self.infcx.tcx.hir();
-        let body = map.body_owned_by(self.mir_def_id());
+        let body = self.infcx.tcx.hir_body_owned_by(self.mir_def_id());
         let expr = &body.value.peel_blocks();
         let mut closure_span = None::<rustc_span::Span>;
         match expr.kind {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index ccd13badad7..b036e6e950b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -424,7 +424,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
         &self,
         argument_index: usize,
     ) -> Option<&hir::Ty<'tcx>> {
-        let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(self.mir_hir_id())?;
+        let fn_decl = self.infcx.tcx.hir_fn_decl_by_hir_id(self.mir_hir_id())?;
         let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?;
         match argument_hir_ty.kind {
             // This indicates a variable with no type annotation, like
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 53cf4f34ae7..a98984a4b4c 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -33,7 +33,6 @@ use rustc_index::{IndexSlice, IndexVec};
 use rustc_infer::infer::{
     InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
 };
-use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::fold::fold_regions;
@@ -188,7 +187,7 @@ fn do_mir_borrowck<'tcx>(
         .iterate_to_fixpoint(tcx, body, Some("borrowck"))
         .into_results_cursor(body);
 
-    let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
+    let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
     let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
 
     // Compute non-lexical lifetimes.
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index d2268c4779d..e0e3e028c61 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -1267,6 +1267,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let sub_region_scc = self.constraint_sccs.scc(sub_region);
         let sup_region_scc = self.constraint_sccs.scc(sup_region);
 
+        if sub_region_scc == sup_region_scc {
+            debug!("{sup_region:?}: {sub_region:?} holds trivially; they are in the same SCC");
+            return true;
+        }
+
         // If we are checking that `'sup: 'sub`, and `'sub` contains
         // some placeholder that `'sup` cannot name, then this is only
         // true if `'sup` outlives static.
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 93081919ec7..84759a0ae04 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -19,7 +19,6 @@ use rustc_infer::infer::{
     BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin,
 };
 use rustc_infer::traits::PredicateObligations;
-use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::traits::query::NoSolution;
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index eb0079a3883..9a68eeb3326 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -21,6 +21,7 @@ use std::iter;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Diag;
 use rustc_hir::BodyOwnerKind;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_index::IndexVec;
@@ -576,7 +577,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let tcx = self.infcx.tcx;
         let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id());
 
-        match tcx.hir().body_owner_kind(self.mir_def) {
+        match tcx.hir_body_owner_kind(self.mir_def) {
             BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
                 let defining_ty = tcx.type_of(self.mir_def).instantiate_identity();
 
@@ -603,7 +604,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
 
             BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => {
                 let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
-                if self.mir_def.to_def_id() == typeck_root_def_id {
+                if self.mir_def.to_def_id() == typeck_root_def_id
+                    // Do not ICE when checking default_field_values consts with lifetimes (#135649)
+                    && DefKind::Field != tcx.def_kind(tcx.parent(typeck_root_def_id))
+                {
                     let args =
                         self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_args);
                     DefiningTy::Const(self.mir_def.to_def_id(), args)
diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
index 521a250ab82..c74efeb59f3 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
@@ -65,7 +65,7 @@ pub(super) fn add_locals_header_comment(fx: &mut FunctionCx<'_, '_, '_>) {
     if fx.clif_comments.enabled() {
         fx.add_global_comment(String::new());
         fx.add_global_comment(
-            "kind  local ty                              size align (abi,pref)".to_string(),
+            "kind  local ty                              size align (abi)".to_string(),
         );
     }
 }
@@ -84,14 +84,13 @@ pub(super) fn add_local_place_comments<'tcx>(
     let (kind, extra) = place.debug_comment();
 
     fx.add_global_comment(format!(
-        "{:<5} {:5} {:30} {:4}b {}, {}{}{}",
+        "{:<5} {:5} {:30} {:4}b {}{}{}",
         kind,
         format!("{:?}", local),
         format!("{:?}", ty),
         size.bytes(),
         align.abi.bytes(),
-        align.pref.bytes(),
-        if extra.is_empty() { "" } else { "              " },
+        if extra.is_empty() { "" } else { "                " },
         extra,
     ));
 }
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 425b2adf32a..bcc70f4567f 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -272,7 +272,7 @@ fn data_id_for_static(
             .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
             .unwrap()
             .align
-            .pref
+            .abi
             .bytes();
 
         let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 2e713171ae0..57c88f4b0f9 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -124,7 +124,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec<
                     crate::constant::codegen_static(tcx, &mut jit_module, def_id);
                 }
                 MonoItem::GlobalAsm(item_id) => {
-                    let item = tcx.hir().item(item_id);
+                    let item = tcx.hir_item(item_id);
                     tcx.dcx().span_fatal(item.span, "Global asm is not supported in JIT mode");
                 }
             }
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index c0a3ce84d52..54745b0d8c1 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -15,7 +15,7 @@ use rustc_target::asm::InlineAsmArch;
 use crate::prelude::*;
 
 pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
-    let item = tcx.hir().item(item_id);
+    let item = tcx.hir_item(item_id);
     if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind {
         let is_x86 =
             matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 94f21ac5f57..a8172270548 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -25,6 +25,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
 rustc_fs_util = { path = "../rustc_fs_util" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_llvm = { path = "../rustc_llvm" }
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 28f423efc21..8c75125e009 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -2,19 +2,18 @@ use std::borrow::Borrow;
 use std::cmp;
 
 use libc::c_uint;
-use rustc_abi as abi;
-pub(crate) use rustc_abi::ExternAbi;
-use rustc_abi::{HasDataLayout, Primitive, Reg, RegKind, Size};
+use rustc_abi::{BackendRepr, HasDataLayout, Primitive, Reg, RegKind, Size};
 use rustc_codegen_ssa::MemFlags;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
 use rustc_codegen_ssa::traits::*;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
-pub(crate) use rustc_middle::ty::layout::{WIDE_PTR_ADDR, WIDE_PTR_EXTRA};
 use rustc_middle::{bug, ty};
 use rustc_session::config;
-pub(crate) use rustc_target::callconv::*;
+use rustc_target::callconv::{
+    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, Conv, FnAbi, PassMode,
+};
 use rustc_target::spec::SanitizerSet;
 use smallvec::SmallVec;
 
@@ -458,7 +457,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         match &self.ret.mode {
             PassMode::Direct(attrs) => {
                 attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
-                if let abi::BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr {
+                if let BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr {
                     apply_range_attr(llvm::AttributePlace::ReturnValue, scalar);
                 }
             }
@@ -499,7 +498,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                 }
                 PassMode::Direct(attrs) => {
                     let i = apply(attrs);
-                    if let abi::BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
+                    if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
                         apply_range_attr(llvm::AttributePlace::Argument(i), scalar);
                     }
                 }
@@ -514,9 +513,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                 PassMode::Pair(a, b) => {
                     let i = apply(a);
                     let ii = apply(b);
-                    if let abi::BackendRepr::ScalarPair(scalar_a, scalar_b) =
-                        arg.layout.backend_repr
-                    {
+                    if let BackendRepr::ScalarPair(scalar_a, scalar_b) = arg.layout.backend_repr {
                         apply_range_attr(llvm::AttributePlace::Argument(i), scalar_a);
                         apply_range_attr(llvm::AttributePlace::Argument(ii), scalar_b);
                     }
@@ -576,7 +573,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         }
         if bx.cx.sess().opts.optimize != config::OptLevel::No
                 && llvm_util::get_version() < (19, 0, 0)
-                && let abi::BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr
+                && let BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr
                 && matches!(scalar.primitive(), Primitive::Int(..))
                 // If the value is a boolean, the range is 0..2 and that ultimately
                 // become 0..0 when the type becomes i1, which would be rejected
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 78b3a7f8541..f17d98fa242 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -7,7 +7,8 @@ use rustc_abi::{AddressSpace, HasDataLayout};
 use rustc_ast::Mutability;
 use rustc_codegen_ssa::common::TypeKind;
 use rustc_codegen_ssa::traits::*;
-use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hashes::Hash128;
 use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 54c5d445f66..4ffe551df09 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -87,7 +87,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
 
 pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
     let omit_gdb_pretty_printer_section =
-        attr::contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
+        attr::contains_name(cx.tcx.hir_krate_attrs(), sym::omit_gdb_pretty_printer_section);
 
     // To ensure the section `__rustc_debug_gdb_scripts_section__` will not create
     // ODR violations at link time, this section will not be emitted for rlibs since
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 59c3fe635d0..98d59f5a8ae 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -11,7 +11,9 @@ use rustc_codegen_ssa::traits::*;
 use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::bug;
-use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{
+    HasTypingEnv, LayoutOf, TyAndLayout, WIDE_PTR_ADDR, WIDE_PTR_EXTRA,
+};
 use rustc_middle::ty::{
     self, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility,
 };
@@ -34,12 +36,12 @@ use crate::common::{AsCCharPtr, CodegenCx};
 use crate::debuginfo::dwarf_const;
 use crate::debuginfo::metadata::type_map::build_type_with_children;
 use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
+use crate::llvm;
 use crate::llvm::debuginfo::{
     DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind,
     DebugNameTableKind,
 };
 use crate::value::Value;
-use crate::{abi, llvm};
 
 impl PartialEq for llvm::Metadata {
     fn eq(&self, other: &Self) -> bool {
@@ -211,16 +213,16 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                     };
 
                     let layout = cx.layout_of(layout_type);
-                    let addr_field = layout.field(cx, abi::WIDE_PTR_ADDR);
-                    let extra_field = layout.field(cx, abi::WIDE_PTR_EXTRA);
+                    let addr_field = layout.field(cx, WIDE_PTR_ADDR);
+                    let extra_field = layout.field(cx, WIDE_PTR_EXTRA);
 
                     let (addr_field_name, extra_field_name) = match wide_pointer_kind {
                         WidePtrKind::Dyn => ("pointer", "vtable"),
                         WidePtrKind::Slice => ("data_ptr", "length"),
                     };
 
-                    assert_eq!(abi::WIDE_PTR_ADDR, 0);
-                    assert_eq!(abi::WIDE_PTR_EXTRA, 1);
+                    assert_eq!(WIDE_PTR_ADDR, 0);
+                    assert_eq!(WIDE_PTR_EXTRA, 1);
 
                     // The data pointer type is a regular, thin pointer, regardless of whether this
                     // is a slice or a trait object.
@@ -242,7 +244,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                             owner,
                             addr_field_name,
                             (addr_field.size, addr_field.align.abi),
-                            layout.fields.offset(abi::WIDE_PTR_ADDR),
+                            layout.fields.offset(WIDE_PTR_ADDR),
                             DIFlags::FlagZero,
                             data_ptr_type_di_node,
                             None,
@@ -252,7 +254,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                             owner,
                             extra_field_name,
                             (extra_field.size, extra_field.align.abi),
-                            layout.fields.offset(abi::WIDE_PTR_EXTRA),
+                            layout.fields.offset(WIDE_PTR_EXTRA),
                             DIFlags::FlagZero,
                             type_di_node(cx, extra_field.ty),
                             None,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 17f2d5f4e73..10819a53b1d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -22,6 +22,7 @@ use rustc_session::config::{self, DebugInfo};
 use rustc_span::{
     BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span, StableSourceFileId, Symbol,
 };
+use rustc_target::callconv::FnAbi;
 use rustc_target::spec::DebuginfoKind;
 use smallvec::SmallVec;
 use tracing::debug;
@@ -29,7 +30,6 @@ use tracing::debug;
 use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, type_di_node};
 use self::namespace::mangled_name_of_instance;
 use self::utils::{DIB, create_DIArray, is_node_local_to_unit};
-use crate::abi::FnAbi;
 use crate::builder::Builder;
 use crate::common::{AsCCharPtr, CodegenCx};
 use crate::llvm;
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index cebceef1b93..e79662ebc64 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -16,10 +16,11 @@ use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_middle::ty::{Instance, Ty};
 use rustc_sanitizers::{cfi, kcfi};
+use rustc_target::callconv::FnAbi;
 use smallvec::SmallVec;
 use tracing::debug;
 
-use crate::abi::{FnAbi, FnAbiLlvmExt};
+use crate::abi::FnAbiLlvmExt;
 use crate::common::AsCCharPtr;
 use crate::context::{CodegenCx, SimpleCx};
 use crate::llvm::AttributePlace::Function;
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 8b976885904..7e1a9d361e6 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1,7 +1,7 @@
 use std::assert_matches::assert_matches;
 use std::cmp::Ordering;
 
-use rustc_abi::{self as abi, Align, Float, HasDataLayout, Primitive, Size};
+use rustc_abi::{Align, BackendRepr, ExternAbi, Float, HasDataLayout, Primitive, Size};
 use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization};
@@ -14,10 +14,11 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, GenericArgsRef, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_span::{Span, Symbol, sym};
+use rustc_target::callconv::{FnAbi, PassMode};
 use rustc_target::spec::{HasTargetSpec, PanicStrategy};
 use tracing::debug;
 
-use crate::abi::{ExternAbi, FnAbi, FnAbiLlvmExt, LlvmType, PassMode};
+use crate::abi::{FnAbiLlvmExt, LlvmType};
 use crate::builder::Builder;
 use crate::context::CodegenCx;
 use crate::llvm::{self, Metadata};
@@ -257,7 +258,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
             }
             sym::va_arg => {
                 match fn_abi.ret.layout.backend_repr {
-                    abi::BackendRepr::Scalar(scalar) => {
+                    BackendRepr::Scalar(scalar) => {
                         match scalar.primitive() {
                             Primitive::Int(..) => {
                                 if self.cx().size_of(ret_ty).bytes() < 4 {
@@ -470,7 +471,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
             }
 
             sym::raw_eq => {
-                use abi::BackendRepr::*;
+                use BackendRepr::*;
                 let tp_ty = fn_args.type_at(0);
                 let layout = self.layout_of(tp_ty).layout;
                 let use_integer_compare = match layout.backend_repr() {
@@ -582,8 +583,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                 }
 
                 let llret_ty = if ret_ty.is_simd()
-                    && let abi::BackendRepr::Memory { .. } =
-                        self.layout_of(ret_ty).layout.backend_repr
+                    && let BackendRepr::Memory { .. } = self.layout_of(ret_ty).layout.backend_repr
                 {
                     let (size, elem_ty) = ret_ty.simd_size_and_type(self.tcx());
                     let elem_ll_ty = match elem_ty.kind() {
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 2afc1efc1b3..963d9258be6 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -25,6 +25,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
 rustc_fs_util = { path = "../rustc_fs_util" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_incremental = { path = "../rustc_incremental" }
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 53953b089c6..84703a0a156 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -15,7 +15,8 @@ use std::fmt::Write;
 
 use rustc_abi::Integer;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hashes::Hash64;
 use rustc_hir::def_id::DefId;
 use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
 use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Mutability};
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index eb4270ffe80..e32d298869b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -1,7 +1,7 @@
 use rustc_abi::Primitive::{Int, Pointer};
 use rustc_abi::{Align, BackendRepr, FieldsShape, Size, TagEncoding, VariantIdx, Variants};
+use rustc_middle::mir::PlaceTy;
 use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
 use rustc_middle::{bug, mir};
diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs
index 6749bc63327..5f95b6615bd 100644
--- a/compiler/rustc_codegen_ssa/src/mono_item.rs
+++ b/compiler/rustc_codegen_ssa/src/mono_item.rs
@@ -35,7 +35,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
                 cx.codegen_static(def_id);
             }
             MonoItem::GlobalAsm(item_id) => {
-                let item = cx.tcx().hir().item(item_id);
+                let item = cx.tcx().hir_item(item_id);
                 if let hir::ItemKind::GlobalAsm(asm) = item.kind {
                     let operands: Vec<_> = asm
                         .operands
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index bfa0a0319c3..52e000858b4 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -31,7 +31,7 @@ pub struct ConstCx<'mir, 'tcx> {
 impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self {
         let typing_env = body.typing_env(tcx);
-        let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local());
+        let const_kind = tcx.hir_body_const_context(body.source.def_id().expect_local());
         ConstCx { body, tcx, typing_env, const_kind }
     }
 
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index a8f83ca13e2..1705af1e210 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -18,6 +18,7 @@ rustc-rayon = { version = "0.5.1", features = ["indexmap"] }
 rustc-stable-hash = { version = "0.1.0", features = ["nightly"] }
 rustc_arena = { path = "../rustc_arena" }
 rustc_graphviz = { path = "../rustc_graphviz" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index 16c66824c5b..c7c0d0ab072 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -1,10 +1,9 @@
 use std::hash::{Hash, Hasher};
 
+use rustc_hashes::Hash64;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
-use crate::stable_hasher::{
-    FromStableHash, Hash64, StableHasherHash, impl_stable_traits_for_trivial_type,
-};
+use crate::stable_hasher::{FromStableHash, StableHasherHash, impl_stable_traits_for_trivial_type};
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs
index 850b052f564..8079212fac5 100644
--- a/compiler/rustc_data_structures/src/intern.rs
+++ b/compiler/rustc_data_structures/src/intern.rs
@@ -92,7 +92,10 @@ impl<'a, T: Ord> Ord for Interned<'a, T> {
     }
 }
 
-impl<'a, T> Hash for Interned<'a, T> {
+impl<'a, T> Hash for Interned<'a, T>
+where
+    T: Hash,
+{
     #[inline]
     fn hash<H: Hasher>(&self, s: &mut H) {
         // Pointer hashing is sufficient, due to the uniqueness constraint.
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 6ef73debadd..66d3834d857 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -84,7 +84,6 @@ pub mod vec_cache;
 pub mod work_queue;
 
 mod atomic_ref;
-mod hashes;
 
 /// This calls the passed function while ensuring it won't be inlined into the caller.
 #[inline(never)]
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 9cd0cc499ca..ffbe54d6206 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -10,12 +10,11 @@ use smallvec::SmallVec;
 #[cfg(test)]
 mod tests;
 
+use rustc_hashes::{Hash64, Hash128};
 pub use rustc_stable_hash::{
     FromStableHash, SipHasher128Hash as StableHasherHash, StableSipHasher128 as StableHasher,
 };
 
-pub use crate::hashes::{Hash64, Hash128};
-
 /// Something that implements `HashStable<CTX>` can be hashed in a way that is
 /// stable across multiple compilation sessions.
 ///
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/tests.rs
index b1bdee18d6d..9c1e4cefa69 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/tests.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/tests.rs
@@ -1,7 +1,8 @@
 use std::ptr;
 
+use rustc_hashes::Hash128;
+
 use super::*;
-use crate::hashes::Hash128;
 use crate::stable_hasher::{HashStable, StableHasher};
 
 /// A tag type used in [`TaggedRef`] tests.
diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs
index 576b1c76823..828a14e707c 100644
--- a/compiler/rustc_driver_impl/src/pretty.rs
+++ b/compiler/rustc_driver_impl/src/pretty.rs
@@ -164,8 +164,7 @@ impl<'tcx> pprust_hir::PpAnn for HirTypedAnn<'tcx> {
         if let pprust_hir::AnnNode::Expr(expr) = node {
             let typeck_results = self.maybe_typeck_results.get().or_else(|| {
                 self.tcx
-                    .hir()
-                    .maybe_body_owned_by(expr.hir_id.owner.def_id)
+                    .hir_maybe_body_owned_by(expr.hir_id.owner.def_id)
                     .map(|body_id| self.tcx.typeck_body(body_id.id()))
             });
 
@@ -273,7 +272,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
                 let attrs = |id| hir_map.attrs(id);
                 pprust_hir::print_crate(
                     sm,
-                    hir_map.root_module(),
+                    tcx.hir_root_module(),
                     src_name,
                     src,
                     &attrs,
@@ -294,7 +293,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
         }
         HirTree => {
             debug!("pretty printing HIR tree");
-            format!("{:#?}", ex.tcx().hir().krate())
+            format!("{:#?}", ex.tcx().hir_crate(()))
         }
         Mir => {
             let mut out = Vec::new();
@@ -317,7 +316,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
             rustc_hir_analysis::check_crate(tcx);
             tcx.dcx().abort_if_errors();
             debug!("pretty printing THIR tree");
-            for did in tcx.hir().body_owners() {
+            for did in tcx.hir_body_owners() {
                 let _ = writeln!(out, "{:?}:\n{}\n", did, thir_tree(tcx, did));
             }
             out
@@ -328,7 +327,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
             rustc_hir_analysis::check_crate(tcx);
             tcx.dcx().abort_if_errors();
             debug!("pretty printing THIR flat");
-            for did in tcx.hir().body_owners() {
+            for did in tcx.hir_body_owners() {
                 let _ = writeln!(out, "{:?}:\n{}\n", did, thir_flat(tcx, did));
             }
             out
diff --git a/compiler/rustc_driver_impl/src/signal_handler.rs b/compiler/rustc_driver_impl/src/signal_handler.rs
index 08b7d937661..e7bc57c9749 100644
--- a/compiler/rustc_driver_impl/src/signal_handler.rs
+++ b/compiler/rustc_driver_impl/src/signal_handler.rs
@@ -6,6 +6,15 @@ use std::{fmt, mem, ptr, slice};
 
 use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE};
 
+/// Signals that represent that we have a bug, and our prompt termination has
+/// been ordered.
+#[rustfmt::skip]
+const KILL_SIGNALS: [(libc::c_int, &str); 3] = [
+    (libc::SIGILL, "SIGILL"),
+    (libc::SIGBUS, "SIGBUS"),
+    (libc::SIGSEGV, "SIGSEGV")
+];
+
 unsafe extern "C" {
     fn backtrace_symbols_fd(buffer: *const *mut libc::c_void, size: libc::c_int, fd: libc::c_int);
 }
@@ -39,8 +48,19 @@ macro raw_errln($tokens:tt) {
 /// # Safety
 ///
 /// Caller must ensure that this function is not re-entered.
-unsafe extern "C" fn print_stack_trace(_: libc::c_int) {
+unsafe extern "C" fn print_stack_trace(signum: libc::c_int) {
     const MAX_FRAMES: usize = 256;
+
+    let signame = {
+        let mut signame = "<unknown>";
+        for sig in KILL_SIGNALS {
+            if sig.0 == signum {
+                signame = sig.1;
+            }
+        }
+        signame
+    };
+
     let stack = unsafe {
         // Reserve data segment so we don't have to malloc in a signal handler, which might fail
         // in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking
@@ -54,7 +74,8 @@ unsafe extern "C" fn print_stack_trace(_: libc::c_int) {
     };
 
     // Just a stack trace is cryptic. Explain what we're doing.
-    raw_errln!("error: rustc interrupted by SIGSEGV, printing backtrace\n");
+    raw_errln!("error: rustc interrupted by {signame}, printing backtrace\n");
+
     let mut written = 1;
     let mut consumed = 0;
     // Begin elaborating return addrs into symbols and writing them directly to stderr
@@ -94,7 +115,7 @@ unsafe extern "C" fn print_stack_trace(_: libc::c_int) {
     written += rem.len() + 1;
 
     let random_depth = || 8 * 16; // chosen by random diceroll (2d20)
-    if cyclic || stack.len() > random_depth() {
+    if (cyclic || stack.len() > random_depth()) && signum == libc::SIGSEGV {
         // technically speculation, but assert it with confidence anyway.
         // rustc only arrived in this signal handler because bad things happened
         // and this message is for explaining it's not the programmer's fault
@@ -106,17 +127,22 @@ unsafe extern "C" fn print_stack_trace(_: libc::c_int) {
         written += 1;
     }
     raw_errln!("note: we would appreciate a report at https://github.com/rust-lang/rust");
-    // get the current stack size WITHOUT blocking and double it
-    let new_size = STACK_SIZE.get().copied().unwrap_or(DEFAULT_STACK_SIZE) * 2;
-    raw_errln!("help: you can increase rustc's stack size by setting RUST_MIN_STACK={new_size}");
-    written += 2;
+    written += 1;
+    if signum == libc::SIGSEGV {
+        // get the current stack size WITHOUT blocking and double it
+        let new_size = STACK_SIZE.get().copied().unwrap_or(DEFAULT_STACK_SIZE) * 2;
+        raw_errln!(
+            "help: you can increase rustc's stack size by setting RUST_MIN_STACK={new_size}"
+        );
+        written += 1;
+    }
     if written > 24 {
-        // We probably just scrolled the earlier "we got SIGSEGV" message off the terminal
-        raw_errln!("note: backtrace dumped due to SIGSEGV! resuming signal");
+        // We probably just scrolled the earlier "interrupted by {signame}" message off the terminal
+        raw_errln!("note: backtrace dumped due to {signame}! resuming signal");
     };
 }
 
-/// When SIGSEGV is delivered to the process, print a stack trace and then exit.
+/// When one of the KILL signals is delivered to the process, print a stack trace and then exit.
 pub(super) fn install() {
     unsafe {
         let alt_stack_size: usize = min_sigstack_size() + 64 * 1024;
@@ -129,7 +155,9 @@ pub(super) fn install() {
         sa.sa_sigaction = print_stack_trace as libc::sighandler_t;
         sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK;
         libc::sigemptyset(&mut sa.sa_mask);
-        libc::sigaction(libc::SIGSEGV, &sa, ptr::null_mut());
+        for (signum, _signame) in KILL_SIGNALS {
+            libc::sigaction(signum, &sa, ptr::null_mut());
+        }
     }
 }
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0803.md b/compiler/rustc_error_codes/src/error_codes/E0803.md
new file mode 100644
index 00000000000..4c022688a2d
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0803.md
@@ -0,0 +1,46 @@
+A trait implementation returns a reference without an
+explicit lifetime linking it to `self`.
+It commonly arises in generic trait implementations
+requiring explicit lifetime bounds.
+
+Erroneous code example:
+
+```compile_fail,E0803
+trait DataAccess<T> {
+    fn get_ref(&self) -> T;
+}
+
+struct Container<'a> {
+    value: &'a f64,
+}
+
+// Attempting to implement reference return
+impl<'a> DataAccess<&f64> for Container<'a> {
+    fn get_ref(&self) -> &f64 { // Error: Lifetime mismatch
+        self.value
+    }
+}
+```
+
+The trait method returns &f64 requiring an independent lifetime
+The struct Container<'a> carries lifetime parameter 'a
+The compiler cannot verify if the returned reference satisfies 'a constraints
+Solution
+Explicitly bind lifetimes to clarify constraints:
+```
+// Modified trait with explicit lifetime binding
+trait DataAccess<'a, T> {
+    fn get_ref(&'a self) -> T;
+}
+
+struct Container<'a> {
+    value: &'a f64,
+}
+
+// Correct implementation (bound lifetimes)
+impl<'a> DataAccess<'a, &'a f64> for Container<'a> {
+    fn get_ref(&'a self) -> &'a f64 {
+        self.value
+    }
+}
+```
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index e970b16f610..098ca42be2b 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -546,6 +546,7 @@ E0799: 0799,
 E0800: 0800,
 E0801: 0801,
 E0802: 0802,
+E0803: 0803,
         );
     )
 }
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index fbb6a1cc475..434f8c1c767 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -14,6 +14,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_codes = { path = "../rustc_error_codes" }
 rustc_error_messages = { path = "../rustc_error_messages" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_lexer = { path = "../rustc_lexer" }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 8ff5dc12596..6fce1fade26 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -58,12 +58,13 @@ pub use emitter::ColorConfig;
 use emitter::{DynEmitter, Emitter, is_case_difference, is_different};
 use rustc_data_structures::AtomicRef;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
-use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
+use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::{DynSend, Lock};
 pub use rustc_error_messages::{
     DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel,
     SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
 };
+use rustc_hashes::Hash128;
 use rustc_lint_defs::LintExpectationId;
 pub use rustc_lint_defs::{Applicability, listify, pluralize};
 use rustc_macros::{Decodable, Encodable};
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 595c8c3279f..721798b0ce4 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -1,10 +1,13 @@
 use std::mem;
 use std::sync::Arc;
 
-use rustc_ast::ExprKind;
 use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, LitKind, Nonterminal, Token, TokenKind};
+use rustc_ast::token::{
+    self, Delimiter, IdentIsRaw, InvisibleOrigin, Lit, LitKind, MetaVarKind, Nonterminal, Token,
+    TokenKind,
+};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
+use rustc_ast::{ExprKind, TyKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize};
 use rustc_parse::lexer::nfc_normalize;
@@ -274,6 +277,33 @@ pub(super) fn transcribe<'a>(
                 // some of the unnecessary whitespace.
                 let ident = MacroRulesNormalizedIdent::new(original_ident);
                 if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
+                    // We wrap the tokens in invisible delimiters, unless they are already wrapped
+                    // in invisible delimiters with the same `MetaVarKind`. Because some proc
+                    // macros can't multiple layers of invisible delimiters of the same
+                    // `MetaVarKind`. This loses some span info, though it hopefully won't matter.
+                    let mut mk_delimited = |mv_kind, mut stream: TokenStream| {
+                        if stream.len() == 1 {
+                            let tree = stream.iter().next().unwrap();
+                            if let TokenTree::Delimited(_, _, delim, inner) = tree
+                                && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mvk)) = delim
+                                && mv_kind == *mvk
+                            {
+                                stream = inner.clone();
+                            }
+                        }
+
+                        // Emit as a token stream within `Delimiter::Invisible` to maintain
+                        // parsing priorities.
+                        marker.visit_span(&mut sp);
+                        // Both the open delim and close delim get the same span, which covers the
+                        // `$foo` in the decl macro RHS.
+                        TokenTree::Delimited(
+                            DelimSpan::from_single(sp),
+                            DelimSpacing::new(Spacing::Alone, Spacing::Alone),
+                            Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)),
+                            stream,
+                        )
+                    };
                     let tt = match cur_matched {
                         MatchedSingle(ParseNtResult::Tt(tt)) => {
                             // `tt`s are emitted into the output stream directly as "raw tokens",
@@ -292,6 +322,13 @@ pub(super) fn transcribe<'a>(
                             let kind = token::NtLifetime(*ident, *is_raw);
                             TokenTree::token_alone(kind, sp)
                         }
+                        MatchedSingle(ParseNtResult::Ty(ty)) => {
+                            let is_path = matches!(&ty.kind, TyKind::Path(None, _path));
+                            mk_delimited(MetaVarKind::Ty { is_path }, TokenStream::from_ast(ty))
+                        }
+                        MatchedSingle(ParseNtResult::Vis(vis)) => {
+                            mk_delimited(MetaVarKind::Vis, TokenStream::from_ast(vis))
+                        }
                         MatchedSingle(ParseNtResult::Nt(nt)) => {
                             // Other variables are emitted into the output stream as groups with
                             // `Delimiter::Invisible` to maintain parsing priorities.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index eb5fac96af2..8eb9bf15829 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1149,7 +1149,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite",
     ),
     rustc_attr!(
-        TEST, pattern_complexity, CrateLevel, template!(NameValueStr: "N"),
+        TEST, pattern_complexity_limit, CrateLevel, template!(NameValueStr: "N"),
         ErrorFollowing, EncodeCrossCrate::No,
     ),
 ];
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index a638a845c07..e852f239aa2 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -227,7 +227,7 @@ declare_features! (
     /// Allows using `#[omit_gdb_pretty_printer_section]`.
     (internal, omit_gdb_pretty_printer_section, "1.5.0", None),
     /// Set the maximum pattern complexity allowed (not limited by default).
-    (internal, pattern_complexity, "1.78.0", None),
+    (internal, pattern_complexity_limit, "1.78.0", None),
     /// Allows using pattern types.
     (internal, pattern_types, "1.79.0", Some(123646)),
     /// Allows using `#[prelude_import]` on glob `use` items.
diff --git a/compiler/rustc_hashes/Cargo.toml b/compiler/rustc_hashes/Cargo.toml
new file mode 100644
index 00000000000..c2bae2fe8cb
--- /dev/null
+++ b/compiler/rustc_hashes/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "rustc_hashes"
+version = "0.0.0"
+edition = "2021"
+
+[dependencies]
+# tidy-alphabetical-start
+rustc-stable-hash = { version = "0.1.0" }
+# tidy-alphabetical-end
diff --git a/compiler/rustc_data_structures/src/hashes.rs b/compiler/rustc_hashes/src/lib.rs
index 8f4639fc2e6..3755caaaa29 100644
--- a/compiler/rustc_data_structures/src/hashes.rs
+++ b/compiler/rustc_hashes/src/lib.rs
@@ -1,6 +1,8 @@
 //! rustc encodes a lot of hashes. If hashes are stored as `u64` or `u128`, a `derive(Encodable)`
 //! will apply varint encoding to the hashes, which is less efficient than directly encoding the 8
-//! or 16 bytes of the hash.
+//! or 16 bytes of the hash. And if that hash depends on the `StableCrateHash` (which most in rustc
+//! do), the varint encoding will make the number of bytes encoded fluctuate between compiler
+//! versions.
 //!
 //! The types in this module represent 64-bit or 128-bit hashes produced by a `StableHasher`.
 //! `Hash64` and `Hash128` expose some utility functions to encourage users to not extract the inner
@@ -14,10 +16,9 @@
 use std::fmt;
 use std::ops::BitXorAssign;
 
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-
-use crate::stable_hasher::{FromStableHash, StableHasherHash};
+use rustc_stable_hash::{FromStableHash, SipHasher128Hash as StableHasherHash};
 
+/// A `u64` but encoded with a fixed size; for hashes this encoding is more compact than `u64`.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
 pub struct Hash64 {
     inner: u64,
@@ -35,26 +36,17 @@ impl Hash64 {
     pub fn as_u64(self) -> u64 {
         self.inner
     }
-}
 
-impl BitXorAssign<u64> for Hash64 {
     #[inline]
-    fn bitxor_assign(&mut self, rhs: u64) {
-        self.inner ^= rhs;
-    }
-}
-
-impl<S: Encoder> Encodable<S> for Hash64 {
-    #[inline]
-    fn encode(&self, s: &mut S) {
-        s.emit_raw_bytes(&self.inner.to_le_bytes());
+    pub fn wrapping_add(self, other: Self) -> Self {
+        Self { inner: self.inner.wrapping_add(other.inner) }
     }
 }
 
-impl<D: Decoder> Decodable<D> for Hash64 {
+impl BitXorAssign<u64> for Hash64 {
     #[inline]
-    fn decode(d: &mut D) -> Self {
-        Self { inner: u64::from_le_bytes(d.read_raw_bytes(8).try_into().unwrap()) }
+    fn bitxor_assign(&mut self, rhs: u64) {
+        self.inner ^= rhs;
     }
 }
 
@@ -79,6 +71,7 @@ impl fmt::LowerHex for Hash64 {
     }
 }
 
+/// A `u128` but encoded with a fixed size; for hashes this encoding is more compact than `u128`.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
 pub struct Hash128 {
     inner: u128,
@@ -96,6 +89,11 @@ impl std::hash::Hash for Hash128 {
 
 impl Hash128 {
     #[inline]
+    pub fn new(n: u128) -> Self {
+        Self { inner: n }
+    }
+
+    #[inline]
     pub fn truncate(self) -> Hash64 {
         Hash64 { inner: self.inner as u64 }
     }
@@ -111,20 +109,6 @@ impl Hash128 {
     }
 }
 
-impl<S: Encoder> Encodable<S> for Hash128 {
-    #[inline]
-    fn encode(&self, s: &mut S) {
-        s.emit_raw_bytes(&self.inner.to_le_bytes());
-    }
-}
-
-impl<D: Decoder> Decodable<D> for Hash128 {
-    #[inline]
-    fn decode(d: &mut D) -> Self {
-        Self { inner: u128::from_le_bytes(d.read_raw_bytes(16).try_into().unwrap()) }
-    }
-}
-
 impl FromStableHash for Hash128 {
     type Hash = StableHasherHash;
 
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index 5bfc4756ec6..b1516e53173 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -10,6 +10,7 @@ rustc_abi = { path = "../rustc_abi" }
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_hir/src/def_path_hash_map.rs b/compiler/rustc_hir/src/def_path_hash_map.rs
index 9a6dee1e511..35c6e57b877 100644
--- a/compiler/rustc_hir/src/def_path_hash_map.rs
+++ b/compiler/rustc_hir/src/def_path_hash_map.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::stable_hasher::Hash64;
+use rustc_hashes::Hash64;
 use rustc_span::def_id::DefIndex;
 
 #[derive(Clone, Default)]
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index dc527240f74..08a0a5225e7 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -7,8 +7,9 @@
 use std::fmt::{self, Write};
 use std::hash::Hash;
 
-use rustc_data_structures::stable_hasher::{Hash64, StableHasher};
+use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::unord::UnordMap;
+use rustc_hashes::Hash64;
 use rustc_index::IndexVec;
 use rustc_macros::{Decodable, Encodable};
 use rustc_span::{Symbol, kw, sym};
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index f632041dba9..bd96fe9ee32 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -18,8 +18,8 @@
 //!    within one another.
 //!    - Example: Examine each expression to look for its type and do some check or other.
 //!    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
-//!      `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use
-//!      `tcx.hir().visit_all_item_likes_in_crate(&mut visitor)`. Within your
+//!      `nested_filter::OnlyBodies` (and implement `maybe_tcx`), and use
+//!      `tcx.hir_visit_all_item_likes_in_crate(&mut visitor)`. Within your
 //!      `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
 //!      `intravisit::walk_expr()` to keep walking the subparts).
 //!    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
@@ -30,8 +30,8 @@
 //!    - Example: Lifetime resolution, which wants to bring lifetimes declared on the
 //!      impl into scope while visiting the impl-items, and then back out again.
 //!    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
-//!      `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with
-//!      `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`.
+//!      `nested_filter::All` (and implement `maybe_tcx`). Walk your crate with
+//!      `tcx.hir_walk_toplevel_module(visitor)`.
 //!    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
 //!    - Pro: Preserves nesting information
 //!    - Con: Does not integrate well into dependency tracking.
@@ -106,45 +106,43 @@ impl<'a> FnKind<'a> {
     }
 }
 
-/// An abstract representation of the HIR `rustc_middle::hir::map::Map`.
-pub trait Map<'hir> {
+/// HIR things retrievable from `TyCtxt`, avoiding an explicit dependence on
+/// `TyCtxt`. The only impls are for `!` (where these functions are never
+/// called) and `TyCtxt` (in `rustc_middle`).
+pub trait HirTyCtxt<'hir> {
     /// Retrieves the `Node` corresponding to `id`.
     fn hir_node(&self, hir_id: HirId) -> Node<'hir>;
-    fn hir_node_by_def_id(&self, def_id: LocalDefId) -> Node<'hir>;
-    fn body(&self, id: BodyId) -> &'hir Body<'hir>;
-    fn item(&self, id: ItemId) -> &'hir Item<'hir>;
-    fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>;
-    fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir>;
-    fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>;
+    fn hir_body(&self, id: BodyId) -> &'hir Body<'hir>;
+    fn hir_item(&self, id: ItemId) -> &'hir Item<'hir>;
+    fn hir_trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>;
+    fn hir_impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir>;
+    fn hir_foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>;
 }
 
-// Used when no map is actually available, forcing manual implementation of nested visitors.
-impl<'hir> Map<'hir> for ! {
+// Used when no tcx is actually available, forcing manual implementation of nested visitors.
+impl<'hir> HirTyCtxt<'hir> for ! {
     fn hir_node(&self, _: HirId) -> Node<'hir> {
-        *self;
+        unreachable!();
     }
-    fn hir_node_by_def_id(&self, _: LocalDefId) -> Node<'hir> {
-        *self;
+    fn hir_body(&self, _: BodyId) -> &'hir Body<'hir> {
+        unreachable!();
     }
-    fn body(&self, _: BodyId) -> &'hir Body<'hir> {
-        *self;
+    fn hir_item(&self, _: ItemId) -> &'hir Item<'hir> {
+        unreachable!();
     }
-    fn item(&self, _: ItemId) -> &'hir Item<'hir> {
-        *self;
+    fn hir_trait_item(&self, _: TraitItemId) -> &'hir TraitItem<'hir> {
+        unreachable!();
     }
-    fn trait_item(&self, _: TraitItemId) -> &'hir TraitItem<'hir> {
-        *self;
+    fn hir_impl_item(&self, _: ImplItemId) -> &'hir ImplItem<'hir> {
+        unreachable!();
     }
-    fn impl_item(&self, _: ImplItemId) -> &'hir ImplItem<'hir> {
-        *self;
-    }
-    fn foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> {
-        *self;
+    fn hir_foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> {
+        unreachable!();
     }
 }
 
 pub mod nested_filter {
-    use super::Map;
+    use super::HirTyCtxt;
 
     /// Specifies what nested things a visitor wants to visit. By "nested
     /// things", we are referring to bits of HIR that are not directly embedded
@@ -159,7 +157,7 @@ pub mod nested_filter {
     /// See the comments at [`rustc_hir::intravisit`] for more details on the overall
     /// visit strategy.
     pub trait NestedFilter<'hir> {
-        type Map: Map<'hir>;
+        type MaybeTyCtxt: HirTyCtxt<'hir>;
 
         /// Whether the visitor visits nested "item-like" things.
         /// E.g., item, impl-item.
@@ -175,10 +173,10 @@ pub mod nested_filter {
     ///
     /// Use this if you are only walking some particular kind of tree
     /// (i.e., a type, or fn signature) and you don't want to thread a
-    /// HIR map around.
+    /// `tcx` around.
     pub struct None(());
     impl NestedFilter<'_> for None {
-        type Map = !;
+        type MaybeTyCtxt = !;
         const INTER: bool = false;
         const INTRA: bool = false;
     }
@@ -195,7 +193,7 @@ use nested_filter::NestedFilter;
 /// (this is why the module is called `intravisit`, to distinguish it
 /// from the AST's `visit` module, which acts differently). If you
 /// simply want to visit all items in the crate in some order, you
-/// should call `tcx.hir().visit_all_item_likes_in_crate`. Otherwise, see the comment
+/// should call `tcx.hir_visit_all_item_likes_in_crate`. Otherwise, see the comment
 /// on `visit_nested_item` for details on how to visit nested items.
 ///
 /// If you want to ensure that your code handles every variant
@@ -203,18 +201,18 @@ use nested_filter::NestedFilter;
 /// to monitor future changes to `Visitor` in case a new method with a
 /// new default implementation gets introduced.)
 pub trait Visitor<'v>: Sized {
-    // this type should not be overridden, it exists for convenient usage as `Self::Map`
-    type Map: Map<'v> = <Self::NestedFilter as NestedFilter<'v>>::Map;
+    // This type should not be overridden, it exists for convenient usage as `Self::MaybeTyCtxt`.
+    type MaybeTyCtxt: HirTyCtxt<'v> = <Self::NestedFilter as NestedFilter<'v>>::MaybeTyCtxt;
 
     ///////////////////////////////////////////////////////////////////////////
     // Nested items.
 
     /// Override this type to control which nested HIR are visited; see
     /// [`NestedFilter`] for details. If you override this type, you
-    /// must also override [`nested_visit_map`](Self::nested_visit_map).
+    /// must also override [`maybe_tcx`](Self::maybe_tcx).
     ///
     /// **If for some reason you want the nested behavior, but don't
-    /// have a `Map` at your disposal:** then override the
+    /// have a `tcx` at your disposal:** then override the
     /// `visit_nested_XXX` methods. If a new `visit_nested_XXX` variant is
     /// added in the future, it will cause a panic which can be detected
     /// and fixed appropriately.
@@ -226,9 +224,9 @@ pub trait Visitor<'v>: Sized {
 
     /// If `type NestedFilter` is set to visit nested items, this method
     /// must also be overridden to provide a map to retrieve nested items.
-    fn nested_visit_map(&mut self) -> Self::Map {
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
         panic!(
-            "nested_visit_map must be implemented or consider using \
+            "maybe_tcx must be implemented or consider using \
             `type NestedFilter = nested_filter::None` (the default)"
         );
     }
@@ -240,10 +238,10 @@ pub trait Visitor<'v>: Sized {
     /// "deep" visit patterns described at
     /// [`rustc_hir::intravisit`]. The only reason to override
     /// this method is if you want a nested pattern but cannot supply a
-    /// [`Map`]; see `nested_visit_map` for advice.
+    /// `TyCtxt`; see `maybe_tcx` for advice.
     fn visit_nested_item(&mut self, id: ItemId) -> Self::Result {
         if Self::NestedFilter::INTER {
-            let item = self.nested_visit_map().item(id);
+            let item = self.maybe_tcx().hir_item(id);
             try_visit!(self.visit_item(item));
         }
         Self::Result::output()
@@ -254,7 +252,7 @@ pub trait Visitor<'v>: Sized {
     /// method.
     fn visit_nested_trait_item(&mut self, id: TraitItemId) -> Self::Result {
         if Self::NestedFilter::INTER {
-            let item = self.nested_visit_map().trait_item(id);
+            let item = self.maybe_tcx().hir_trait_item(id);
             try_visit!(self.visit_trait_item(item));
         }
         Self::Result::output()
@@ -265,7 +263,7 @@ pub trait Visitor<'v>: Sized {
     /// method.
     fn visit_nested_impl_item(&mut self, id: ImplItemId) -> Self::Result {
         if Self::NestedFilter::INTER {
-            let item = self.nested_visit_map().impl_item(id);
+            let item = self.maybe_tcx().hir_impl_item(id);
             try_visit!(self.visit_impl_item(item));
         }
         Self::Result::output()
@@ -276,7 +274,7 @@ pub trait Visitor<'v>: Sized {
     /// method.
     fn visit_nested_foreign_item(&mut self, id: ForeignItemId) -> Self::Result {
         if Self::NestedFilter::INTER {
-            let item = self.nested_visit_map().foreign_item(id);
+            let item = self.maybe_tcx().hir_foreign_item(id);
             try_visit!(self.visit_foreign_item(item));
         }
         Self::Result::output()
@@ -287,7 +285,7 @@ pub trait Visitor<'v>: Sized {
     /// `Self::NestedFilter`.
     fn visit_nested_body(&mut self, id: BodyId) -> Self::Result {
         if Self::NestedFilter::INTRA {
-            let body = self.nested_visit_map().body(id);
+            let body = self.maybe_tcx().hir_body(id);
             try_visit!(self.visit_body(body));
         }
         Self::Result::output()
diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs
index e0e63d183c6..0837444ffdb 100644
--- a/compiler/rustc_hir/src/tests.rs
+++ b/compiler/rustc_hir/src/tests.rs
@@ -1,6 +1,6 @@
 #![allow(rustc::symbol_intern_string_literal)]
 
-use rustc_data_structures::stable_hasher::Hash64;
+use rustc_hashes::Hash64;
 use rustc_span::def_id::{DefPathHash, StableCrateId};
 use rustc_span::edition::Edition;
 use rustc_span::{Symbol, create_session_globals_then};
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 5560d087e96..47d5976be09 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -387,6 +387,8 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation
 
 hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
 
+hir_analysis_no_variant_named = no variant named `{$ident}` found for enum `{$ty}`
+
 hir_analysis_not_supported_delegation = {$descr}
     .label = callee defined here
 
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
deleted file mode 100644
index 9b02651a8bd..00000000000
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-//! Bounds are restrictions applied to some types after they've been lowered from the HIR to the
-//! [`rustc_middle::ty`] form.
-
-use rustc_hir::LangItem;
-use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
-use rustc_span::Span;
-
-/// Collects together a list of type bounds. These lists of bounds occur in many places
-/// in Rust's syntax:
-///
-/// ```text
-/// trait Foo: Bar + Baz { }
-///            ^^^^^^^^^ supertrait list bounding the `Self` type parameter
-///
-/// fn foo<T: Bar + Baz>() { }
-///           ^^^^^^^^^ bounding the type parameter `T`
-///
-/// impl dyn Bar + Baz
-///          ^^^^^^^^^ bounding the type-erased dynamic type
-/// ```
-///
-/// Our representation is a bit mixed here -- in some cases, we
-/// include the self type (e.g., `trait_bounds`) but in others we do not
-#[derive(Default, PartialEq, Eq, Clone, Debug)]
-pub(crate) struct Bounds<'tcx> {
-    clauses: Vec<(ty::Clause<'tcx>, Span)>,
-}
-
-impl<'tcx> Bounds<'tcx> {
-    pub(crate) fn push_region_bound(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        region: ty::PolyTypeOutlivesPredicate<'tcx>,
-        span: Span,
-    ) {
-        self.clauses
-            .push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).upcast(tcx), span));
-    }
-
-    pub(crate) fn push_trait_bound(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        bound_trait_ref: ty::PolyTraitRef<'tcx>,
-        span: Span,
-        polarity: ty::PredicatePolarity,
-    ) {
-        let clause = (
-            bound_trait_ref
-                .map_bound(|trait_ref| {
-                    ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
-                })
-                .upcast(tcx),
-            span,
-        );
-        // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
-        if tcx.is_lang_item(bound_trait_ref.def_id(), LangItem::Sized) {
-            self.clauses.insert(0, clause);
-        } else {
-            self.clauses.push(clause);
-        }
-    }
-
-    pub(crate) fn push_projection_bound(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        projection: ty::PolyProjectionPredicate<'tcx>,
-        span: Span,
-    ) {
-        self.clauses.push((
-            projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).upcast(tcx),
-            span,
-        ));
-    }
-
-    pub(crate) fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
-        let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
-        let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]);
-        // Preferable to put this obligation first, since we report better errors for sized ambiguity.
-        self.clauses.insert(0, (trait_ref.upcast(tcx), span));
-    }
-
-    /// Push a `const` or `~const` bound as a `HostEffect` predicate.
-    pub(crate) fn push_const_bound(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        bound_trait_ref: ty::PolyTraitRef<'tcx>,
-        constness: ty::BoundConstness,
-        span: Span,
-    ) {
-        if tcx.is_const_trait(bound_trait_ref.def_id()) {
-            self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, constness), span));
-        } else {
-            tcx.dcx().span_delayed_bug(span, "tried to lower {host:?} bound for non-const trait");
-        }
-    }
-
-    pub(crate) fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
-        self.clauses.iter().cloned()
-    }
-}
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 71a10ad3a0c..516ecbcfe0e 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -124,7 +124,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
 
     for field in &def.non_enum_variant().fields {
         if !allowed_union_or_unsafe_field(tcx, field.ty(tcx, args), typing_env, span) {
-            let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
+            let (field_span, ty_span) = match tcx.hir_get_if_local(field.did) {
                 // We are currently checking the type this field came from, so it must be local.
                 Some(Node::Field(field)) => (field.span, field.ty.span),
                 _ => unreachable!("mir field has to correspond to hir field"),
@@ -435,8 +435,8 @@ fn best_definition_site_of_opaque<'tcx>(
     impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
         type NestedFilter = nested_filter::All;
         type Result = ControlFlow<(Span, LocalDefId)>;
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.tcx.hir()
+        fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+            self.tcx
         }
         fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {
             if let hir::ExprKind::Closure(closure) = ex.kind {
@@ -484,7 +484,7 @@ fn best_definition_site_of_opaque<'tcx>(
         hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
             let scope = tcx.hir().get_defining_scope(tcx.local_def_id_to_hir_id(opaque_def_id));
             let found = if scope == hir::CRATE_HIR_ID {
-                tcx.hir().walk_toplevel_module(&mut locator)
+                tcx.hir_walk_toplevel_module(&mut locator)
             } else {
                 match tcx.hir_node(scope) {
                     Node::Item(it) => locator.visit_item(it),
@@ -880,7 +880,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                             .emit();
                         }
 
-                        let item = tcx.hir().foreign_item(item.id);
+                        let item = tcx.hir_foreign_item(item.id);
                         match &item.kind {
                             hir::ForeignItemKind::Fn(sig, _, _) => {
                                 require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span);
@@ -1494,7 +1494,7 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
                 // In the case the discriminant is both a duplicate and overflowed, let the user know
                 if let hir::Node::AnonConst(expr) =
                     tcx.hir_node_by_def_id(discr_def_id.expect_local())
-                    && let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
+                    && let hir::ExprKind::Lit(lit) = &tcx.hir_body(expr.body).value.kind
                     && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
                     && *lit_value != dis.val
                 {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index bb5087e864c..c193aad2afd 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -501,7 +501,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
 
     let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id);
-    let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
+    let return_span = tcx.hir_fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
     let cause = ObligationCause::new(
         return_span,
         impl_m_def_id,
@@ -658,11 +658,10 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
                 "method `{}` has an incompatible return type for trait",
                 trait_m.name
             );
-            let hir = tcx.hir();
             infcx.err_ctxt().note_type_err(
                 &mut diag,
                 &cause,
-                hir.get_if_local(impl_m.def_id)
+                tcx.hir_get_if_local(impl_m.def_id)
                     .and_then(|node| node.fn_decl())
                     .map(|decl| (decl.output.span(), Cow::from("return type in trait"), false)),
                 Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound {
@@ -1034,8 +1033,7 @@ fn report_trait_method_mismatch<'tcx>(
             // argument pattern and type.
             let (sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn();
             let span = tcx
-                .hir()
-                .body_param_names(body)
+                .hir_body_param_names(body)
                 .zip(sig.decl.inputs.iter())
                 .map(|(param, ty)| param.span.to(ty.span))
                 .next()
@@ -1123,15 +1121,14 @@ fn check_region_bounds_on_impl_item<'tcx>(
     // the moment, give a kind of vague error message.
     if trait_params != impl_params {
         let span = tcx
-            .hir()
-            .get_generics(impl_m.def_id.expect_local())
+            .hir_get_generics(impl_m.def_id.expect_local())
             .expect("expected impl item to have generics or else we can't compare them")
             .span;
 
         let mut generics_span = None;
         let mut bounds_span = vec![];
         let mut where_span = None;
-        if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id)
+        if let Some(trait_node) = tcx.hir_get_if_local(trait_m.def_id)
             && let Some(trait_generics) = trait_node.generics()
         {
             generics_span = Some(trait_generics.span);
@@ -1146,7 +1143,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
                     }
                 }
             }
-            if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id)
+            if let Some(impl_node) = tcx.hir_get_if_local(impl_m.def_id)
                 && let Some(impl_generics) = impl_node.generics()
             {
                 let mut impl_bounds = 0;
@@ -2107,18 +2104,21 @@ pub(super) fn check_type_bounds<'tcx>(
         ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
     };
 
-    let mut obligations: Vec<_> = tcx
-        .explicit_item_bounds(trait_ty.def_id)
-        .iter_instantiated_copied(tcx, rebased_args)
-        .map(|(concrete_ty_bound, span)| {
-            debug!(?concrete_ty_bound);
-            traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
-        })
-        .collect();
+    let mut obligations: Vec<_> = util::elaborate(
+        tcx,
+        tcx.explicit_item_bounds(trait_ty.def_id).iter_instantiated_copied(tcx, rebased_args).map(
+            |(concrete_ty_bound, span)| {
+                debug!(?concrete_ty_bound);
+                traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
+            },
+        ),
+    )
+    .collect();
 
     // Only in a const implementation do we need to check that the `~const` item bounds hold.
     if tcx.is_conditionally_const(impl_ty_def_id) {
-        obligations.extend(
+        obligations.extend(util::elaborate(
+            tcx,
             tcx.explicit_implied_const_bounds(trait_ty.def_id)
                 .iter_instantiated_copied(tcx, rebased_args)
                 .map(|(c, span)| {
@@ -2129,7 +2129,7 @@ pub(super) fn check_type_bounds<'tcx>(
                         c.to_host_effect_clause(tcx, ty::BoundConstness::Maybe),
                     )
                 }),
-        );
+        ));
     }
     debug!(item_bounds=?obligations);
 
@@ -2137,26 +2137,19 @@ pub(super) fn check_type_bounds<'tcx>(
     // to its definition type. This should be the param-env we use to *prove* the
     // predicate too, but we don't do that because of performance issues.
     // See <https://github.com/rust-lang/rust/pull/117542#issue-1976337685>.
-    let trait_projection_ty = Ty::new_projection_from_args(tcx, trait_ty.def_id, rebased_args);
-    let impl_identity_ty = tcx.type_of(impl_ty.def_id).instantiate_identity();
     let normalize_param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref);
-    for mut obligation in util::elaborate(tcx, obligations) {
-        let normalized_predicate = if infcx.next_trait_solver() {
-            obligation.predicate.fold_with(&mut ReplaceTy {
-                tcx,
-                from: trait_projection_ty,
-                to: impl_identity_ty,
-            })
-        } else {
-            ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate)
-        };
-        debug!(?normalized_predicate);
-        obligation.predicate = normalized_predicate;
-
-        ocx.register_obligation(obligation);
+    for obligation in &mut obligations {
+        match ocx.deeply_normalize(&normalize_cause, normalize_param_env, obligation.predicate) {
+            Ok(pred) => obligation.predicate = pred,
+            Err(e) => {
+                return Err(infcx.err_ctxt().report_fulfillment_errors(e));
+            }
+        }
     }
+
     // Check that all obligations are satisfied by the implementation's
     // version.
+    ocx.register_obligations(obligations);
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
         let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
@@ -2168,22 +2161,6 @@ pub(super) fn check_type_bounds<'tcx>(
     ocx.resolve_regions_and_report_errors(impl_ty_def_id, param_env, assumed_wf_types)
 }
 
-struct ReplaceTy<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    from: Ty<'tcx>,
-    to: Ty<'tcx>,
-}
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceTy<'tcx> {
-    fn cx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if self.from == ty { self.to } else { ty.super_fold_with(self) }
-    }
-}
-
 /// Install projection predicates that allow GATs to project to their own
 /// definition types. This is not allowed in general in cases of default
 /// associated types in trait definitions, or when specialization is involved,
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index 0e9e9b48ab3..4973d848959 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -96,7 +96,7 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
 
         // This opaque also needs to be from the impl method -- otherwise,
         // it's a refinement to a TAIT.
-        if !tcx.hir().get_if_local(impl_opaque.def_id).is_some_and(|node| {
+        if !tcx.hir_get_if_local(impl_opaque.def_id).is_some_and(|node| {
             matches!(
                 node.expect_opaque_ty().origin,
                 hir::OpaqueTyOrigin::AsyncFn { parent, .. }  | hir::OpaqueTyOrigin::FnReturn { parent, .. }
@@ -327,7 +327,7 @@ fn report_mismatched_rpitit_signature<'tcx>(
             hir::FnRetTy::Return(ty) => (ty.span, ty.span, "", ""),
         };
     let trait_return_span =
-        tcx.hir().get_if_local(trait_m_def_id).map(|node| match node.fn_decl().unwrap().output {
+        tcx.hir_get_if_local(trait_m_def_id).map(|node| match node.fn_decl().unwrap().output {
             hir::FnRetTy::DefaultReturn(_) => tcx.def_span(trait_m_def_id),
             hir::FnRetTy::Return(ty) => ty.span,
         });
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 96b33bdd250..7b3c3ea2bb4 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -129,7 +129,7 @@ fn get_owner_return_paths(
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
     let parent_id = tcx.hir().get_parent_item(hir_id).def_id;
     tcx.hir_node_by_def_id(parent_id).body_id().map(|body_id| {
-        let body = tcx.hir().body(body_id);
+        let body = tcx.hir_body(body_id);
         let mut visitor = ReturnsVisitor::default();
         visitor.visit_body(body);
         (parent_id, visitor)
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index d43c65c0023..255f5fee52a 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -424,7 +424,7 @@ fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hi
         // that share the parent environment. We handle const blocks in
         // `visit_inline_const`.
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
-            let body = visitor.tcx.hir().body(body);
+            let body = visitor.tcx.hir_body(body);
             visitor.visit_body(body);
         }
         hir::ExprKind::AssignOp(_, left_expr, right_expr) => {
@@ -844,7 +844,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
 
     fn visit_body(&mut self, body: &hir::Body<'tcx>) {
         let body_id = body.id();
-        let owner_id = self.tcx.hir().body_owner_def_id(body_id);
+        let owner_id = self.tcx.hir_body_owner_def_id(body_id);
 
         debug!(
             "visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})",
@@ -855,7 +855,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
         );
 
         self.enter_body(body.value.hir_id, |this| {
-            if this.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() {
+            if this.tcx.hir_body_owner_kind(owner_id).is_fn_or_closure() {
                 // The arguments and `self` are parented to the fn.
                 this.cx.var_parent = this.cx.parent.take();
                 for param in body.params {
@@ -906,7 +906,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
         resolve_local(self, Some(l.pat), l.init)
     }
     fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
-        let body = self.tcx.hir().body(c.body);
+        let body = self.tcx.hir_body(c.body);
         self.visit_body(body);
     }
 }
@@ -924,7 +924,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
         return tcx.region_scope_tree(typeck_root_def_id);
     }
 
-    let scope_tree = if let Some(body) = tcx.hir().maybe_body_owned_by(def_id.expect_local()) {
+    let scope_tree = if let Some(body) = tcx.hir_maybe_body_owned_by(def_id.expect_local()) {
         let mut visitor = ScopeResolutionVisitor {
             tcx,
             scope_tree: ScopeTree::default(),
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 4218f4ef0c1..edfa897860b 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1163,7 +1163,7 @@ fn check_type_defn<'tcx>(
                     // be refactored to check the instantiate-ability of the code better.
                     if let Some(def_id) = def_id.as_local()
                         && let hir::Node::AnonConst(anon) = tcx.hir_node_by_def_id(def_id)
-                        && let expr = &tcx.hir().body(anon.body).value
+                        && let expr = &tcx.hir_body(anon.body).value
                         && let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
                         && let Res::Def(DefKind::ConstParam, _def_id) = path.res
                     {
@@ -1710,7 +1710,7 @@ fn check_sized_if_body<'tcx>(
     maybe_span: Option<Span>,
 ) {
     let tcx = wfcx.tcx();
-    if let Some(body) = tcx.hir().maybe_body_owned_by(def_id) {
+    if let Some(body) = tcx.hir_maybe_body_owned_by(def_id) {
         let span = maybe_span.unwrap_or(body.value.span);
 
         wfcx.register_bound(
diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index 68b7b44c36d..750c09887a1 100644
--- a/compiler/rustc_hir_analysis/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -13,11 +13,11 @@ pub(crate) fn provide(providers: &mut Providers) {
 fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) {
     let mut used_trait_imports = UnordSet::<LocalDefId>::default();
 
-    // FIXME: Use `tcx.hir().par_body_owners()` when we implement creating `DefId`s
+    // FIXME: Use `tcx.hir_par_body_owners()` when we implement creating `DefId`s
     // for anon constants during their parents' typeck.
     // Doing so at current will produce queries cycle errors because it may typeck
     // on anon constants directly.
-    for item_def_id in tcx.hir().body_owners() {
+    for item_def_id in tcx.hir_body_owners() {
         let imports = tcx.used_trait_imports(item_def_id);
         debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
         used_trait_imports.extend_unord(imports.items().copied());
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 9da57c330c5..b46b805f0a9 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -679,7 +679,7 @@ fn infringing_fields_error<'tcx>(
 
     suggest_constraining_type_params(
         tcx,
-        tcx.hir().get_generics(impl_did).expect("impls always have generics"),
+        tcx.hir_get_generics(impl_did).expect("impls always have generics"),
         &mut err,
         bounds
             .iter()
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index a86dede48bf..c9a9180c5c9 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -25,7 +25,7 @@ pub(crate) fn crate_inherent_impls(
     let mut collect = InherentCollect { tcx, impls_map: Default::default() };
 
     let mut res = Ok(());
-    for id in tcx.hir().items() {
+    for id in tcx.hir_free_items() {
         res = res.and(collect.check_item(id));
     }
 
@@ -113,7 +113,7 @@ impl<'tcx> InherentCollect<'tcx> {
         ty: Ty<'tcx>,
     ) -> Result<(), ErrorGuaranteed> {
         let items = self.tcx.associated_item_def_ids(impl_def_id);
-        if !self.tcx.hir().rustc_coherence_is_core() {
+        if !self.tcx.hir_rustc_coherence_is_core() {
             if self.tcx.features().rustc_attrs() {
                 for &impl_item in items {
                     if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index c72f6201831..dc616576c9c 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -18,7 +18,7 @@ pub(crate) fn crate_inherent_impls_overlap_check(
 ) -> Result<(), ErrorGuaranteed> {
     let mut inherent_overlap_checker = InherentOverlapChecker { tcx };
     let mut res = Ok(());
-    for id in tcx.hir().items() {
+    for id in tcx.hir_free_items() {
         res = res.and(inherent_overlap_checker.check_item(id));
     }
     res
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 12623779956..75ea207a06b 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -277,8 +277,8 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
 impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -669,7 +669,7 @@ fn get_new_lifetime_name<'tcx>(
 
 #[instrument(level = "debug", skip_all)]
 fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
-    let it = tcx.hir().item(item_id);
+    let it = tcx.hir_item(item_id);
     debug!(item = %it.ident, id = %it.hir_id());
     let def_id = item_id.owner_id.def_id;
     let icx = ItemCtxt::new(tcx, def_id);
@@ -683,7 +683,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
         | hir::ItemKind::GlobalAsm(_) => {}
         hir::ItemKind::ForeignMod { items, .. } => {
             for item in *items {
-                let item = tcx.hir().foreign_item(item.id);
+                let item = tcx.hir_foreign_item(item.id);
                 tcx.ensure_ok().generics_of(item.owner_id);
                 tcx.ensure_ok().type_of(item.owner_id);
                 tcx.ensure_ok().predicates_of(item.owner_id);
@@ -790,7 +790,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
 }
 
 fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
-    let trait_item = tcx.hir().trait_item(trait_item_id);
+    let trait_item = tcx.hir_trait_item(trait_item_id);
     let def_id = trait_item_id.owner_id;
     tcx.ensure_ok().generics_of(def_id);
     let icx = ItemCtxt::new(tcx, def_id.def_id);
@@ -865,7 +865,7 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
     tcx.ensure_ok().generics_of(def_id);
     tcx.ensure_ok().type_of(def_id);
     tcx.ensure_ok().predicates_of(def_id);
-    let impl_item = tcx.hir().impl_item(impl_item_id);
+    let impl_item = tcx.hir_impl_item(impl_item_id);
     let icx = ItemCtxt::new(tcx, def_id.def_id);
     match impl_item.kind {
         hir::ImplItemKind::Fn(..) => {
@@ -1769,7 +1769,7 @@ fn coroutine_for_closure(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DefId {
                 ..
             }),
         ..
-    } = tcx.hir().body(body).value
+    } = tcx.hir_body(body).value
     else {
         bug!()
     };
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
index 41f8465ae91..63c445fa6a3 100644
--- a/compiler/rustc_hir_analysis/src/collect/dump.rs
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -52,7 +52,7 @@ pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) {
 }
 
 pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
-    for iid in tcx.hir().items() {
+    for iid in tcx.hir_free_items() {
         let did = iid.owner_id.def_id;
         if tcx.has_attr(did, sym::rustc_dump_def_parents) {
             struct AnonConstFinder<'tcx> {
@@ -63,8 +63,8 @@ pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
             impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> {
                 type NestedFilter = nested_filter::All;
 
-                fn nested_visit_map(&mut self) -> Self::Map {
-                    self.tcx.hir()
+                fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+                    self.tcx
                 }
 
                 fn visit_anon_const(&mut self, c: &'tcx rustc_hir::AnonConst) {
@@ -77,7 +77,7 @@ pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
             // the `rustc_dump_def_parents` attribute to the anon const so it would not be possible
             // to see what its def parent is.
             let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: vec![] };
-            intravisit::walk_item(&mut anon_ct_finder, tcx.hir().item(iid));
+            intravisit::walk_item(&mut anon_ct_finder, tcx.hir_item(iid));
 
             for did in [did].into_iter().chain(anon_ct_finder.anon_consts) {
                 let span = tcx.def_span(did);
@@ -99,14 +99,14 @@ pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
 }
 
 pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
-    for id in tcx.hir().items() {
+    for id in tcx.hir_free_items() {
         let def_id = id.owner_id.def_id;
 
         let Some(attr) = tcx.get_attr(def_id, sym::rustc_dump_vtable) else {
             continue;
         };
 
-        let vtable_entries = match tcx.hir().item(id).kind {
+        let vtable_entries = match tcx.hir_item(id).kind {
             hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
                 let trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate_identity();
                 if trait_ref.has_non_region_param() {
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 41c4cfbaa82..1c1a246cc15 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -13,7 +13,6 @@ use tracing::{debug, instrument};
 
 use super::ItemCtxt;
 use super::predicates_of::assert_only_contains_predicates_from;
-use crate::bounds::Bounds;
 use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter};
 
 /// For associated types we include both bounds written on the type
@@ -38,7 +37,7 @@ fn associated_type_bounds<'tcx>(
         );
 
         let icx = ItemCtxt::new(tcx, assoc_item_def_id);
-        let mut bounds = Bounds::default();
+        let mut bounds = Vec::new();
         icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
         // Associated types are implicitly sized unless a `?Sized` bound is found
         match filter {
@@ -68,7 +67,7 @@ fn associated_type_bounds<'tcx>(
                 )
             });
 
-        let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent));
+        let all_bounds = tcx.arena.alloc_from_iter(bounds.into_iter().chain(bounds_from_parent));
         debug!(
             "associated_type_bounds({}) = {:?}",
             tcx.def_path_str(assoc_item_def_id.to_def_id()),
@@ -327,7 +326,7 @@ fn opaque_type_bounds<'tcx>(
 ) -> &'tcx [(ty::Clause<'tcx>, Span)] {
     ty::print::with_reduced_queries!({
         let icx = ItemCtxt::new(tcx, opaque_def_id);
-        let mut bounds = Bounds::default();
+        let mut bounds = Vec::new();
         icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
         match filter {
@@ -343,7 +342,7 @@ fn opaque_type_bounds<'tcx>(
         }
         debug!(?bounds);
 
-        tcx.arena.alloc_from_iter(bounds.clauses())
+        tcx.arena.alloc_slice(&bounds)
     })
 }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index d94383d6f3d..7b1fff157b5 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -13,7 +13,6 @@ use rustc_span::{DUMMY_SP, Ident, Span};
 use tracing::{debug, instrument, trace};
 
 use super::item_bounds::explicit_item_bounds_with_filter;
-use crate::bounds::Bounds;
 use crate::collect::ItemCtxt;
 use crate::constrained_generic_params as cgp;
 use crate::delegation::inherit_predicates_for_delegation_item;
@@ -178,7 +177,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // 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 {
-        let mut bounds = Bounds::default();
+        let mut bounds = Vec::new();
         icx.lowerer().lower_bounds(
             tcx.types.self_param,
             self_bounds,
@@ -186,7 +185,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             ty::List::empty(),
             PredicateFilter::All,
         );
-        predicates.extend(bounds.clauses());
+        predicates.extend(bounds);
     }
 
     // In default impls, we can assume that the self type implements
@@ -209,7 +208,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             GenericParamKind::Lifetime { .. } => (),
             GenericParamKind::Type { .. } => {
                 let param_ty = icx.lowerer().lower_ty_param(param.hir_id);
-                let mut bounds = Bounds::default();
+                let mut bounds = Vec::new();
                 // Params are implicitly sized unless a `?Sized` bound is found
                 icx.lowerer().add_sized_bound(
                     &mut bounds,
@@ -219,7 +218,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     param.span,
                 );
                 trace!(?bounds);
-                predicates.extend(bounds.clauses());
+                predicates.extend(bounds);
                 trace!(?predicates);
             }
             hir::GenericParamKind::Const { .. } => {
@@ -264,7 +263,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     }
                 }
 
-                let mut bounds = Bounds::default();
+                let mut bounds = Vec::new();
                 icx.lowerer().lower_bounds(
                     ty,
                     bound_pred.bounds,
@@ -272,7 +271,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     bound_vars,
                     PredicateFilter::All,
                 );
-                predicates.extend(bounds.clauses());
+                predicates.extend(bounds);
             }
 
             hir::WherePredicateKind::RegionPredicate(region_pred) => {
@@ -436,7 +435,7 @@ fn const_evaluatable_predicates_of<'tcx>(
         self_ty.instantiate_identity().visit_with(&mut collector);
     }
 
-    if let Some(_) = tcx.hir().fn_sig_by_hir_id(hir_id) {
+    if let Some(_) = tcx.hir_fn_sig_by_hir_id(hir_id) {
         debug!("visit fn sig");
         let fn_sig = tcx.fn_sig(def_id);
         let fn_sig = fn_sig.instantiate_identity();
@@ -627,7 +626,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
     let icx = ItemCtxt::new(tcx, trait_def_id);
 
     let self_param_ty = tcx.types.self_param;
-    let mut bounds = Bounds::default();
+    let mut bounds = Vec::new();
     icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter);
 
     let where_bounds_that_match =
@@ -635,7 +634,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
 
     // Combine the two lists to form the complete set of superbounds:
     let implied_bounds =
-        &*tcx.arena.alloc_from_iter(bounds.clauses().chain(where_bounds_that_match));
+        &*tcx.arena.alloc_from_iter(bounds.into_iter().chain(where_bounds_that_match));
     debug!(?implied_bounds);
 
     // Now require that immediate supertraits are lowered, which will, in
@@ -826,7 +825,7 @@ pub(super) fn type_param_predicates<'tcx>(
     // `where T: Foo`.
 
     let param_id = tcx.local_def_id_to_hir_id(def_id);
-    let param_owner = tcx.hir().ty_param_owner(def_id);
+    let param_owner = tcx.hir_ty_param_owner(def_id);
 
     // Don't look for bounds where the type parameter isn't in scope.
     let parent = if item_def_id == param_owner {
@@ -904,7 +903,7 @@ impl<'tcx> ItemCtxt<'tcx> {
         param_def_id: LocalDefId,
         filter: PredicateFilter,
     ) -> Vec<(ty::Clause<'tcx>, Span)> {
-        let mut bounds = Bounds::default();
+        let mut bounds = Vec::new();
 
         for predicate in hir_generics.predicates {
             let hir_id = predicate.hir_id;
@@ -938,7 +937,7 @@ impl<'tcx> ItemCtxt<'tcx> {
             );
         }
 
-        bounds.clauses().collect()
+        bounds
     }
 }
 
@@ -1007,7 +1006,7 @@ pub(super) fn const_conditions<'tcx>(
     };
 
     let icx = ItemCtxt::new(tcx, def_id);
-    let mut bounds = Bounds::default();
+    let mut bounds = Vec::new();
 
     for pred in generics.predicates {
         match pred.kind {
@@ -1027,12 +1026,12 @@ pub(super) fn const_conditions<'tcx>(
     }
 
     if let Some((def_id, supertraits)) = trait_def_id_and_supertraits {
-        bounds.push_const_bound(
-            tcx,
-            ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())),
-            ty::BoundConstness::Maybe,
+        // We've checked above that the trait is conditionally const.
+        bounds.push((
+            ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id()))
+                .to_host_effect_clause(tcx, ty::BoundConstness::Maybe),
             DUMMY_SP,
-        );
+        ));
 
         icx.lowerer().lower_bounds(
             tcx.types.self_param,
@@ -1045,7 +1044,7 @@ pub(super) fn const_conditions<'tcx>(
 
     ty::ConstConditions {
         parent: has_parent.then(|| tcx.local_parent(def_id).to_def_id()),
-        predicates: tcx.arena.alloc_from_iter(bounds.clauses().map(|(clause, span)| {
+        predicates: tcx.arena.alloc_from_iter(bounds.into_iter().map(|(clause, span)| {
             (
                 clause.kind().map_bound(|clause| match clause {
                     ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index c03a1f6240f..759c981a8f7 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -422,12 +422,12 @@ enum NonLifetimeBinderAllowed {
 impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let body = self.tcx.hir().body(body);
+        let body = self.tcx.hir_body(body);
         self.with(Scope::Body { id: body.id(), s: self.scope }, |this| {
             this.visit_body(body);
         });
@@ -1049,7 +1049,7 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectL
     match param.source {
         hir::GenericParamSource::Generics => {
             let parent_def_id = tcx.local_parent(param_def_id);
-            let generics = tcx.hir().get_generics(parent_def_id).unwrap();
+            let generics = tcx.hir_get_generics(parent_def_id).unwrap();
             let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id);
             let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap();
 
@@ -1250,7 +1250,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
                         && let hir::LifetimeName::Param(param_id) = lifetime_ref.res
                         && let Some(generics) =
-                            self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
+                            self.tcx.hir_get_generics(self.tcx.local_parent(param_id))
                         && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
                         && param.is_elided_lifetime()
                         && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
@@ -1264,7 +1264,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                         );
 
                         if let Some(generics) =
-                            self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id)
+                            self.tcx.hir_get_generics(lifetime_ref.hir_id.owner.def_id)
                         {
                             let new_param_sugg =
                                 if let Some(span) = generics.span_for_lifetime_suggestion() {
@@ -1340,7 +1340,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 };
                 def = ResolvedArg::Error(guar);
             } else if let Some(body_id) = outermost_body {
-                let fn_id = self.tcx.hir().body_owner(body_id);
+                let fn_id = self.tcx.hir_body_owner(body_id);
                 match self.tcx.hir_node(fn_id) {
                     Node::Item(hir::Item { owner_id, kind: hir::ItemKind::Fn { .. }, .. })
                     | Node::TraitItem(hir::TraitItem {
@@ -2265,8 +2265,8 @@ fn is_late_bound_map(
     tcx: TyCtxt<'_>,
     owner_id: hir::OwnerId,
 ) -> Option<&FxIndexSet<hir::ItemLocalId>> {
-    let sig = tcx.hir().fn_sig_by_hir_id(owner_id.into())?;
-    let generics = tcx.hir().get_generics(owner_id.def_id)?;
+    let sig = tcx.hir_fn_sig_by_hir_id(owner_id.into())?;
+    let generics = tcx.hir_get_generics(owner_id.def_id)?;
 
     let mut late_bound = FxIndexSet::default();
 
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 4e12db190fd..293a095b41d 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -451,7 +451,7 @@ fn infer_placeholder_type<'tcx>(
                     );
                 } else {
                     with_forced_trimmed_paths!(err.span_note(
-                        tcx.hir().body(body_id).value.span,
+                        tcx.hir_body(body_id).value.span,
                         format!("however, the inferred type `{ty}` cannot be named"),
                     ));
                 }
@@ -494,7 +494,7 @@ fn infer_placeholder_type<'tcx>(
                     );
                 } else {
                     with_forced_trimmed_paths!(diag.span_note(
-                        tcx.hir().body(body_id).value.span,
+                        tcx.hir_body(body_id).value.span,
                         format!("however, the inferred type `{ty}` cannot be named"),
                     ));
                 }
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index e2b9fe0f9f7..0c36888f363 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -89,7 +89,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
     debug!(?scope);
 
     if scope == hir::CRATE_HIR_ID {
-        tcx.hir().walk_toplevel_module(&mut locator);
+        tcx.hir_walk_toplevel_module(&mut locator);
     } else {
         trace!("scope={:#?}", tcx.hir_node(scope));
         match tcx.hir_node(scope) {
@@ -298,8 +298,8 @@ impl TaitConstraintLocator<'_> {
 impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
         if let hir::ExprKind::Closure(closure) = ex.kind {
@@ -441,8 +441,8 @@ impl RpitConstraintChecker<'_> {
 impl<'tcx> intravisit::Visitor<'tcx> for RpitConstraintChecker<'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
         if let hir::ExprKind::Closure(closure) = ex.kind {
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 14ea10461cb..1a0b0edb257 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1417,6 +1417,15 @@ pub(crate) struct CrossCrateTraitsDefined {
     pub traits: String,
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_analysis_no_variant_named, code = E0599)]
+pub struct NoVariantNamed<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub ident: Ident,
+    pub ty: Ty<'tcx>,
+}
+
 // FIXME(fmease): Deduplicate:
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index b2501d647a5..681e8e36d58 100644
--- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -451,7 +451,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
                 )
             });
 
-        let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(hir::Node::fn_sig);
+        let fn_sig = self.tcx.hir_get_if_local(self.def_id).and_then(hir::Node::fn_sig);
         let is_used_in_input = |def_id| {
             fn_sig.is_some_and(|fn_sig| {
                 fn_sig.decl.inputs.iter().any(|ty| match ty.kind {
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 ef6167907b5..75c97001c32 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -8,7 +8,7 @@ use rustc_hir::HirId;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::bug;
-use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt};
+use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt, Upcast};
 use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
 use rustc_trait_selection::traits;
 use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
@@ -16,7 +16,6 @@ use smallvec::SmallVec;
 use tracing::{debug, instrument};
 
 use super::errors::GenericsArgsErrExtend;
-use crate::bounds::Bounds;
 use crate::errors;
 use crate::hir_ty_lowering::{
     AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason,
@@ -28,7 +27,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// Doesn't add the bound if the HIR bounds contain any of `Sized`, `?Sized` or `!Sized`.
     pub(crate) fn add_sized_bound(
         &self,
-        bounds: &mut Bounds<'tcx>,
+        bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         self_ty: Ty<'tcx>,
         hir_bounds: &'tcx [hir::GenericBound<'tcx>],
         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
@@ -113,10 +112,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound {
             // There was in fact a `?Sized`, `!Sized` or explicit `Sized` bound;
             // we don't need to do anything.
-        } else if sized_def_id.is_some() {
+        } else if let Some(sized_def_id) = sized_def_id {
             // There was no `?Sized`, `!Sized` or explicit `Sized` bound;
             // add `Sized` if it's available.
-            bounds.push_sized(tcx, self_ty, span);
+            let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [self_ty]);
+            // Preferable to put this obligation first, since we report better errors for sized ambiguity.
+            bounds.insert(0, (trait_ref.upcast(tcx), span));
         }
     }
 
@@ -146,7 +147,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         &self,
         param_ty: Ty<'tcx>,
         hir_bounds: I,
-        bounds: &mut Bounds<'tcx>,
+        bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
         predicate_filter: PredicateFilter,
     ) where
@@ -189,14 +190,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     }
 
                     let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound);
-                    bounds.push_region_bound(
-                        self.tcx(),
-                        ty::Binder::bind_with_vars(
-                            ty::OutlivesPredicate(param_ty, region),
-                            bound_vars,
-                        ),
-                        lifetime.ident.span,
+                    let bound = ty::Binder::bind_with_vars(
+                        ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(param_ty, region)),
+                        bound_vars,
                     );
+                    bounds.push((bound.upcast(self.tcx()), lifetime.ident.span));
                 }
                 hir::GenericBound::Use(..) => {
                     // We don't actually lower `use` into the type layer.
@@ -219,7 +217,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         hir_ref_id: hir::HirId,
         trait_ref: ty::PolyTraitRef<'tcx>,
         constraint: &hir::AssocItemConstraint<'tcx>,
-        bounds: &mut Bounds<'tcx>,
+        bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         duplicates: &mut FxIndexMap<DefId, Span>,
         path_span: Span,
         predicate_filter: PredicateFilter,
@@ -389,14 +387,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     PredicateFilter::All
                     | PredicateFilter::SelfOnly
                     | PredicateFilter::SelfAndAssociatedTypeBounds => {
-                        bounds.push_projection_bound(
-                            tcx,
-                            projection_term.map_bound(|projection_term| ty::ProjectionPredicate {
+                        let bound = projection_term.map_bound(|projection_term| {
+                            ty::ClauseKind::Projection(ty::ProjectionPredicate {
                                 projection_term,
                                 term,
-                            }),
-                            constraint.span,
-                        );
+                            })
+                        });
+                        bounds.push((bound.upcast(tcx), constraint.span));
                     }
                     // SelfTraitThatDefines is only interested in trait predicates.
                     PredicateFilter::SelfTraitThatDefines(_) => {}
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 a8b37fa5054..830dca0d3cd 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
@@ -17,7 +17,6 @@ use smallvec::{SmallVec, smallvec};
 use tracing::{debug, instrument};
 
 use super::HirTyLowerer;
-use crate::bounds::Bounds;
 use crate::hir_ty_lowering::{
     GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason,
 };
@@ -36,7 +35,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let tcx = self.tcx();
         let dummy_self = tcx.types.trait_object_dummy_self;
 
-        let mut user_written_bounds = Bounds::default();
+        let mut user_written_bounds = Vec::new();
         let mut potential_assoc_types = Vec::new();
         for trait_bound in hir_bounds.iter() {
             if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity {
@@ -60,15 +59,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
 
         let (trait_bounds, mut projection_bounds) =
-            traits::expand_trait_aliases(tcx, user_written_bounds.clauses());
+            traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
         let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds
             .into_iter()
             .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
         // We  don't support empty trait objects.
         if regular_traits.is_empty() && auto_traits.is_empty() {
-            let guar =
-                self.report_trait_object_with_no_traits_error(span, user_written_bounds.clauses());
+            let guar = self.report_trait_object_with_no_traits_error(
+                span,
+                user_written_bounds.iter().copied(),
+            );
             return Ty::new_error(tcx, guar);
         }
         // We don't support >1 principal
@@ -84,7 +85,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // Check that there are no gross dyn-compatibility violations;
         // most importantly, that the supertraits don't contain `Self`,
         // to avoid ICEs.
-        for (clause, span) in user_written_bounds.clauses() {
+        for (clause, span) in user_written_bounds {
             if let Some(trait_pred) = clause.as_trait_clause() {
                 let violations =
                     hir_ty_lowering_dyn_compatibility_violations(tcx, trait_pred.def_id());
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 7eb982a3179..d2789cc0fd6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -225,7 +225,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     && let item_def_id =
                         tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(ty_param_def_id))
                     // FIXME: ...which obviously won't have any generics.
-                    && let Some(generics) = tcx.hir().get_generics(item_def_id.def_id)
+                    && let Some(generics) = tcx.hir_get_generics(item_def_id.def_id)
                 {
                     // FIXME: Suggest adding supertrait bounds if we have a `Self` type param.
                     // FIXME(trait_alias): Suggest adding `Self: Trait` to
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index 43137397870..17de64db629 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -70,7 +70,7 @@ fn generic_arg_mismatch_err(
             }
             Res::Def(DefKind::TyParam, src_def_id) => {
                 if let Some(param_local_id) = param.def_id.as_local() {
-                    let param_name = tcx.hir().ty_param_name(param_local_id);
+                    let param_name = tcx.hir_ty_param_name(param_local_id);
                     let param_type = tcx.type_of(param.def_id).instantiate_identity();
                     if param_type.is_suggestable(tcx, false) {
                         err.span_suggestion(
@@ -110,7 +110,7 @@ fn generic_arg_mismatch_err(
                 err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));
                 err.help("function item types cannot be named directly");
             } else if let hir::ConstArgKind::Anon(anon) = cnst.kind
-                && let body = tcx.hir().body(anon.body)
+                && let body = tcx.hir_body(anon.body)
                 && let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) =
                     body.value.kind
                 && let Res::Def(DefKind::Fn { .. }, id) = path.res
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 88323db6dda..e9b99caf737 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -49,11 +49,13 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
+use rustc_type_ir::Upcast;
 use tracing::{debug, instrument};
 
-use crate::bounds::Bounds;
 use crate::check::check_abi_fn_ptr;
-use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType};
+use crate::errors::{
+    AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, NoVariantNamed,
+};
 use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
 use crate::middle::resolve_bound_vars as rbv;
@@ -217,7 +219,7 @@ impl AssocItemQSelf {
     fn to_string(&self, tcx: TyCtxt<'_>) -> String {
         match *self {
             Self::Trait(def_id) => tcx.def_path_str(def_id),
-            Self::TyParam(def_id, _) => tcx.hir().ty_param_name(def_id).to_string(),
+            Self::TyParam(def_id, _) => tcx.hir_ty_param_name(def_id).to_string(),
             Self::SelfTyAlias => kw::SelfUpper.to_string(),
         }
     }
@@ -342,8 +344,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
 
             rbv::ResolvedArg::EarlyBound(def_id) => {
-                let name = tcx.hir().ty_param_name(def_id);
-                let item_def_id = tcx.hir().ty_param_owner(def_id);
+                let name = tcx.hir_ty_param_name(def_id);
+                let item_def_id = tcx.hir_ty_param_owner(def_id);
                 let generics = tcx.generics_of(item_def_id);
                 let index = generics.param_def_id_to_index[&def_id.to_def_id()];
                 ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name })
@@ -691,7 +693,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         constness: hir::BoundConstness,
         polarity: hir::BoundPolarity,
         self_ty: Ty<'tcx>,
-        bounds: &mut Bounds<'tcx>,
+        bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         predicate_filter: PredicateFilter,
     ) -> GenericArgCountResult {
         let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
@@ -720,6 +722,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             bound_vars,
         );
 
+        debug!(?poly_trait_ref);
+
         let polarity = match polarity {
             rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive,
             rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative,
@@ -741,6 +745,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         };
 
+        // We deal with const conditions later.
+        match predicate_filter {
+            PredicateFilter::All
+            | PredicateFilter::SelfOnly
+            | PredicateFilter::SelfTraitThatDefines(..)
+            | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                let bound = poly_trait_ref.map_bound(|trait_ref| {
+                    ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
+                });
+                let bound = (bound.upcast(tcx), span);
+                // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
+                if tcx.is_lang_item(trait_def_id, rustc_hir::LangItem::Sized) {
+                    bounds.insert(0, bound);
+                } else {
+                    bounds.push(bound);
+                }
+            }
+            PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
+        }
+
         if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness
             && !self.tcx().is_const_trait(trait_def_id)
         {
@@ -765,58 +789,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 suggestion_pre,
                 suggestion,
             });
-        }
-
-        match predicate_filter {
-            // This is only concerned with trait predicates.
-            PredicateFilter::SelfTraitThatDefines(..) => {
-                bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
-            }
-            PredicateFilter::All
-            | PredicateFilter::SelfOnly
-            | PredicateFilter::SelfAndAssociatedTypeBounds => {
-                debug!(?poly_trait_ref);
-                bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
-
-                match constness {
-                    hir::BoundConstness::Always(span) => {
-                        if polarity == ty::PredicatePolarity::Positive {
-                            bounds.push_const_bound(
-                                tcx,
-                                poly_trait_ref,
-                                ty::BoundConstness::Const,
-                                span,
-                            );
+        } else {
+            match predicate_filter {
+                // This is only concerned with trait predicates.
+                PredicateFilter::SelfTraitThatDefines(..) => {}
+                PredicateFilter::All
+                | PredicateFilter::SelfOnly
+                | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                    match constness {
+                        hir::BoundConstness::Always(span) => {
+                            if polarity == ty::PredicatePolarity::Positive {
+                                bounds.push((
+                                    poly_trait_ref
+                                        .to_host_effect_clause(tcx, ty::BoundConstness::Const),
+                                    span,
+                                ));
+                            }
                         }
+                        hir::BoundConstness::Maybe(_) => {
+                            // We don't emit a const bound here, since that would mean that we
+                            // unconditionally need to prove a `HostEffect` predicate, even when
+                            // the predicates are being instantiated in a non-const context. This
+                            // is instead handled in the `const_conditions` query.
+                        }
+                        hir::BoundConstness::Never => {}
                     }
-                    hir::BoundConstness::Maybe(_) => {
-                        // We don't emit a const bound here, since that would mean that we
-                        // unconditionally need to prove a `HostEffect` predicate, even when
-                        // the predicates are being instantiated in a non-const context. This
-                        // is instead handled in the `const_conditions` query.
-                    }
-                    hir::BoundConstness::Never => {}
                 }
-            }
-            // On the flip side, when filtering `ConstIfConst` bounds, we only need to convert
-            // `~const` bounds. All other predicates are handled in their respective queries.
-            //
-            // Note that like `PredicateFilter::SelfOnly`, we don't need to do any filtering
-            // here because we only call this on self bounds, and deal with the recursive case
-            // in `lower_assoc_item_constraint`.
-            PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => match constness {
-                hir::BoundConstness::Maybe(span) => {
-                    if polarity == ty::PredicatePolarity::Positive {
-                        bounds.push_const_bound(
-                            tcx,
-                            poly_trait_ref,
-                            ty::BoundConstness::Maybe,
-                            span,
-                        );
+                // On the flip side, when filtering `ConstIfConst` bounds, we only need to convert
+                // `~const` bounds. All other predicates are handled in their respective queries.
+                //
+                // Note that like `PredicateFilter::SelfOnly`, we don't need to do any filtering
+                // here because we only call this on self bounds, and deal with the recursive case
+                // in `lower_assoc_item_constraint`.
+                PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {
+                    match constness {
+                        hir::BoundConstness::Maybe(span) => {
+                            if polarity == ty::PredicatePolarity::Positive {
+                                bounds.push((
+                                    poly_trait_ref
+                                        .to_host_effect_clause(tcx, ty::BoundConstness::Maybe),
+                                    span,
+                                ));
+                            }
+                        }
+                        hir::BoundConstness::Always(_) | hir::BoundConstness::Never => {}
                     }
                 }
-                hir::BoundConstness::Always(_) | hir::BoundConstness::Never => {}
-            },
+            }
         }
 
         let mut dup_constraints = FxIndexMap::default();
@@ -1188,14 +1207,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     let msg = format!("expected type, found variant `{assoc_ident}`");
                     self.dcx().span_err(span, msg)
                 } else if qself_ty.is_enum() {
-                    let mut err = struct_span_code_err!(
-                        self.dcx(),
-                        assoc_ident.span,
-                        E0599,
-                        "no variant named `{}` found for enum `{}`",
-                        assoc_ident,
-                        qself_ty,
-                    );
+                    let mut err = self.dcx().create_err(NoVariantNamed {
+                        span: assoc_ident.span,
+                        ident: assoc_ident,
+                        ty: qself_ty,
+                    });
 
                     let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
                     if let Some(variant_name) = find_best_match_for_name(
@@ -1976,7 +1992,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     if let Some(hir::Node::Item(&hir::Item {
                         kind: hir::ItemKind::Impl(impl_),
                         ..
-                    })) = tcx.hir().get_if_local(def_id)
+                    })) = tcx.hir_get_if_local(def_id)
                     {
                         err.span_note(impl_.self_ty.span, "not a concrete type");
                     }
@@ -2053,10 +2069,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 Ty::new_bound(tcx, debruijn, br)
             }
             Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
-                let item_def_id = tcx.hir().ty_param_owner(def_id);
+                let item_def_id = tcx.hir_ty_param_owner(def_id);
                 let generics = tcx.generics_of(item_def_id);
                 let index = generics.param_def_id_to_index[&def_id.to_def_id()];
-                Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id))
+                Ty::new_param(tcx, index, tcx.hir_ty_param_name(def_id))
             }
             Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar),
             arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
@@ -2213,7 +2229,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> {
         let tcx = self.tcx();
 
-        let expr = &tcx.hir().body(anon.body).value;
+        let expr = &tcx.hir_body(anon.body).value;
         debug!(?expr);
 
         let ty = tcx
@@ -2382,7 +2398,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // Impl trait in bindings lower as an infer var with additional
                 // set of type bounds.
                 let self_ty = self.ty_infer(None, hir_ty.span);
-                let mut bounds = Bounds::default();
+                let mut bounds = Vec::new();
                 self.lower_bounds(
                     self_ty,
                     hir_bounds.iter(),
@@ -2390,11 +2406,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     ty::List::empty(),
                     PredicateFilter::All,
                 );
-                self.register_trait_ascription_bounds(
-                    bounds.clauses().collect(),
-                    hir_ty.hir_id,
-                    hir_ty.span,
-                );
+                self.register_trait_ascription_bounds(bounds, hir_ty.hir_id, hir_ty.span);
                 self_ty
             }
             // If we encounter a type relative path with RTN generics, then it must have
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index f5abcd23440..0b1be8e4f7a 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -22,8 +22,6 @@ fn diagnostic_hir_wf_check<'tcx>(
     tcx: TyCtxt<'tcx>,
     (predicate, loc): (ty::Predicate<'tcx>, WellFormedLoc),
 ) -> Option<ObligationCause<'tcx>> {
-    let hir = tcx.hir();
-
     let def_id = match loc {
         WellFormedLoc::Ty(def_id) => def_id,
         WellFormedLoc::Param { function, param_idx: _ } => function,
@@ -187,7 +185,7 @@ fn diagnostic_hir_wf_check<'tcx>(
             ref node => bug!("Unexpected node {:?}", node),
         },
         WellFormedLoc::Param { function: _, param_idx } => {
-            let fn_decl = hir.fn_decl_by_hir_id(hir_id).unwrap();
+            let fn_decl = tcx.hir_fn_decl_by_hir_id(hir_id).unwrap();
             // Get return type
             if param_idx as usize == fn_decl.inputs.len() {
                 match fn_decl.output {
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 8a529e9c686..0859a39b155 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -80,7 +80,6 @@ This API is completely unstable and subject to change.
 pub mod check;
 
 pub mod autoderef;
-mod bounds;
 mod check_unused;
 mod coherence;
 mod collect;
@@ -93,6 +92,7 @@ mod impl_wf_check;
 mod outlives;
 mod variance;
 
+pub use errors::NoVariantNamed;
 use rustc_abi::ExternAbi;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
@@ -184,7 +184,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
         // what we are intending to discard, to help future type-based refactoring.
         type R = Result<(), ErrorGuaranteed>;
 
-        tcx.hir().par_for_each_module(|module| {
+        tcx.par_hir_for_each_module(|module| {
             let _: R = tcx.ensure_ok().check_mod_type_wf(module);
         });
 
@@ -209,7 +209,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
 
     // Make sure we evaluate all static and (non-associated) const items, even if unused.
     // If any of these fail to evaluate, we do not want this crate to pass compilation.
-    tcx.hir().par_body_owners(|item_def_id| {
+    tcx.par_hir_body_owners(|item_def_id| {
         let def_kind = tcx.def_kind(item_def_id);
         match def_kind {
             DefKind::Static { .. } => tcx.ensure_ok().eval_static_initializer(item_def_id),
@@ -227,7 +227,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
     // for anon constants during their parents' typeck.
     // Typeck all body owners in parallel will produce queries
     // cycle errors because it may typeck on anon constants directly.
-    tcx.hir().par_body_owners(|item_def_id| {
+    tcx.par_hir_body_owners(|item_def_id| {
         let def_kind = tcx.def_kind(item_def_id);
         if !matches!(def_kind, DefKind::AnonConst) {
             tcx.ensure_ok().typeck(item_def_id);
diff --git a/compiler/rustc_hir_analysis/src/outlives/dump.rs b/compiler/rustc_hir_analysis/src/outlives/dump.rs
index ab50d9e86ef..4233896c372 100644
--- a/compiler/rustc_hir_analysis/src/outlives/dump.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/dump.rs
@@ -3,7 +3,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::sym;
 
 pub(crate) fn inferred_outlives(tcx: TyCtxt<'_>) {
-    for id in tcx.hir().items() {
+    for id in tcx.hir_free_items() {
         if !tcx.has_attr(id.owner_id, sym::rustc_outlives) {
             continue;
         }
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index 036163b9f14..a0faa5e8429 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -28,7 +28,7 @@ pub(super) fn infer_predicates(
         let mut predicates_added = false;
 
         // Visit all the crates and infer predicates
-        for id in tcx.hir().items() {
+        for id in tcx.hir_free_items() {
             let item_did = id.owner_id;
 
             debug!("InferVisitor::visit_item(item={:?})", item_did);
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 56e268aea54..7343ba80854 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -25,8 +25,8 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::{FileName, Ident, Span, Symbol, kw};
 use {rustc_ast as ast, rustc_hir as hir};
 
-pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: HirId) -> String {
-    to_string(&map, |s| s.print_node(map.hir_node(hir_id)))
+pub fn id_to_string(cx: &dyn rustc_hir::intravisit::HirTyCtxt<'_>, hir_id: HirId) -> String {
+    to_string(&cx, |s| s.print_node(cx.hir_node(hir_id)))
 }
 
 pub enum AnnNode<'a> {
@@ -55,15 +55,15 @@ pub trait PpAnn {
     fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
 }
 
-impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> {
+impl PpAnn for &dyn rustc_hir::intravisit::HirTyCtxt<'_> {
     fn nested(&self, state: &mut State<'_>, nested: Nested) {
         match nested {
-            Nested::Item(id) => state.print_item(self.item(id)),
-            Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
-            Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
-            Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)),
-            Nested::Body(id) => state.print_expr(self.body(id).value),
-            Nested::BodyParamPat(id, i) => state.print_pat(self.body(id).params[i].pat),
+            Nested::Item(id) => state.print_item(self.hir_item(id)),
+            Nested::TraitItem(id) => state.print_trait_item(self.hir_trait_item(id)),
+            Nested::ImplItem(id) => state.print_impl_item(self.hir_impl_item(id)),
+            Nested::ForeignItem(id) => state.print_foreign_item(self.hir_foreign_item(id)),
+            Nested::Body(id) => state.print_expr(self.hir_body(id).value),
+            Nested::BodyParamPat(id, i) => state.print_pat(self.hir_body(id).params[i].pat),
         }
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 3d40c5ee804..38319862334 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -213,10 +213,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         arm_ty: Ty<'tcx>,
         prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>,
     ) {
-        let hir = self.tcx.hir();
-
         // First, check that we're actually in the tail of a function.
-        let Some(body) = hir.maybe_body_owned_by(self.body_id) else {
+        let Some(body) = self.tcx.hir_maybe_body_owned_by(self.body_id) else {
             return;
         };
         let hir::ExprKind::Block(block, _) = body.value.kind else {
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index f2d0b911731..49ea2181b07 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -708,8 +708,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let Res::Local(_) = path.res
             && let [segment] = &path.segments
         {
-            for id in self.tcx.hir().items() {
-                if let Some(node) = self.tcx.hir().get_if_local(id.owner_id.into())
+            for id in self.tcx.hir_free_items() {
+                if let Some(node) = self.tcx.hir_get_if_local(id.owner_id.into())
                     && let hir::Node::Item(item) = node
                     && let hir::ItemKind::Fn { .. } = item.kind
                     && item.ident.name == segment.ident.name
@@ -860,7 +860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
-        let host = match self.tcx.hir().body_const_context(self.body_id) {
+        let host = match self.tcx.hir_body_const_context(self.body_id) {
             Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => {
                 ty::BoundConstness::Const
             }
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 6fb5f6af091..dabae7b1d09 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -35,12 +35,8 @@ pub(super) fn check_fn<'a, 'tcx>(
     params_can_be_unsized: bool,
 ) -> Option<CoroutineTypes<'tcx>> {
     let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id);
-
     let tcx = fcx.tcx;
-    let hir = tcx.hir();
-
     let declared_ret_ty = fn_sig.output();
-
     let ret_ty =
         fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
             declared_ret_ty,
@@ -69,7 +65,7 @@ pub(super) fn check_fn<'a, 'tcx>(
     });
 
     // Add formal parameters.
-    let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
+    let inputs_hir = tcx.hir_fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
     let inputs_fn = fn_sig.inputs().iter().copied();
     for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
         // We checked the root's signature during wfcheck, but not the child.
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 43124f44ca6..71a0664bbdf 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -51,7 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
-        let body = tcx.hir().body(closure.body);
+        let body = tcx.hir_body(closure.body);
         let expr_def_id = closure.def_id;
 
         // It's always helpful for inference if we know the kind of
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index ad378367e30..cf11bccae0a 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1891,7 +1891,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 kind: hir::ExprKind::Closure(&hir::Closure { body, .. }),
                 ..
             }) = parent
-            && !matches!(fcx.tcx.hir().body(body).value.kind, hir::ExprKind::Block(..))
+            && !matches!(fcx.tcx.hir_body(body).value.kind, hir::ExprKind::Block(..))
         {
             fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
         }
@@ -1943,7 +1943,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         if due_to_block
             && let Some(expr) = expression
             && let Some(parent_fn_decl) =
-                fcx.tcx.hir().fn_decl_by_hir_id(fcx.tcx.local_def_id_to_hir_id(fcx.body_id))
+                fcx.tcx.hir_fn_decl_by_hir_id(fcx.tcx.local_def_id_to_hir_id(fcx.body_id))
         {
             fcx.suggest_missing_break_or_return_expr(
                 &mut err,
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 85e949952f8..4dc736f72cf 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -293,8 +293,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'_>,
         source: TypeMismatchSource<'tcx>,
     ) -> bool {
-        let hir = self.tcx.hir();
-
         let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else {
             return false;
         };
@@ -334,7 +332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let mut expr_finder = FindExprs { hir_id: local_hir_id, uses: init.into_iter().collect() };
-        let body = hir.body_owned_by(self.body_id);
+        let body = self.tcx.hir_body_owned_by(self.body_id);
         expr_finder.visit_expr(body.value);
 
         // Replaces all of the variables in the given type with a fresh inference variable.
@@ -727,7 +725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             ident,
                             kind: hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..),
                             ..
-                        })) = self.tcx.hir().get_if_local(*def_id)
+                        })) = self.tcx.hir_get_if_local(*def_id)
                         {
                             primary_span = ty.span;
                             secondary_span = ident.span;
@@ -1173,7 +1171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if let Some(hir::Node::Item(hir::Item {
                     kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }),
                     ..
-                })) = self.tcx.hir().get_if_local(*alias_to)
+                })) = self.tcx.hir_get_if_local(*alias_to)
                 {
                     err.span_label(self_ty.span, "this is the type of the `Self` literal");
                 }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 9ccd6746087..1c63b8b3655 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -19,6 +19,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, HirId, QPath};
+use rustc_hir_analysis::NoVariantNamed;
 use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _};
 use rustc_infer::infer;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
@@ -1150,13 +1151,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // We are inside a function body, so reporting "return statement
             // outside of function body" needs an explanation.
 
-            let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id);
+            let encl_body_owner_id = self.tcx.hir_enclosing_body_owner(expr.hir_id);
 
             // If this didn't hold, we would not have to report an error in
             // the first place.
             assert_ne!(encl_item_id.def_id, encl_body_owner_id);
 
-            let encl_body = self.tcx.hir().body_owned_by(encl_body_owner_id);
+            let encl_body = self.tcx.hir_body_owned_by(encl_body_owner_id);
 
             err.encl_body_span = Some(encl_body.value.span);
             err.encl_fn_span = Some(*encl_fn_span);
@@ -1801,7 +1802,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         block: &'tcx hir::ConstBlock,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        let body = self.tcx.hir().body(block.body);
+        let body = self.tcx.hir_body(block.body);
 
         // Create a new function context.
         let def_id = block.def_id;
@@ -3229,7 +3230,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             None => return,
         };
         let param_span = self.tcx.hir().span(param_hir_id);
-        let param_name = self.tcx.hir().ty_param_name(param_def_id.expect_local());
+        let param_name = self.tcx.hir_ty_param_name(param_def_id.expect_local());
 
         err.span_label(param_span, format!("type parameter '{param_name}' declared here"));
     }
@@ -3837,15 +3838,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .iter_enumerated()
                         .find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident)
                     else {
-                        type_error_struct!(
-                            self.dcx(),
-                            ident.span,
-                            container,
-                            E0599,
-                            "no variant named `{ident}` found for enum `{container}`",
-                        )
-                        .with_span_label(field.span, "variant not found")
-                        .emit();
+                        self.dcx()
+                            .create_err(NoVariantNamed { span: ident.span, ident, ty: container })
+                            .with_span_label(field.span, "variant not found")
+                            .emit_unless(container.references_error());
                         break;
                     };
                     let Some(&subfield) = fields.next() else {
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 860e619be71..9b85b2aeec6 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -1001,11 +1001,12 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
         let closure_def_id = closure_expr.def_id;
         // For purposes of this function, coroutine and closures are equivalent.
         let body_owner_is_closure = matches!(
-            tcx.hir().body_owner_kind(self.cx.body_owner_def_id()),
+            tcx.hir_body_owner_kind(self.cx.body_owner_def_id()),
             hir::BodyOwnerKind::Closure
         );
 
-        // If we have a nested closure, we want to include the fake reads present in the nested closure.
+        // If we have a nested closure, we want to include the fake reads present in the nested
+        // closure.
         if let Some(fake_reads) = self.cx.typeck_results().closure_fake_reads.get(&closure_def_id) {
             for (fake_read, cause, hir_id) in fake_reads.iter() {
                 match fake_read.base {
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 4618c5d3849..e051fc7ac6c 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -573,7 +573,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         coercions: &VecGraph<ty::TyVid, true>,
     ) -> errors::SuggestAnnotations {
         let body =
-            self.tcx.hir().maybe_body_owned_by(self.body_id).expect("body id must have an owner");
+            self.tcx.hir_maybe_body_owned_by(self.body_id).expect("body id must have an owner");
         // For each diverging var, look through the HIR for a place to give it
         // a type annotation. We do this per var because we only really need one
         // suggestion to influence a var to be `()`.
@@ -687,7 +687,7 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
         if let hir::ExprKind::Closure(&hir::Closure { body, .. })
         | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) = expr.kind
         {
-            self.visit_body(self.fcx.tcx.hir().body(body))?;
+            self.visit_body(self.fcx.tcx.hir_body(body))?;
         }
 
         // Try to suggest adding an explicit qself `()` to a trait method path.
@@ -764,7 +764,7 @@ fn compute_unsafe_infer_vars<'a, 'tcx>(
     fcx: &'a FnCtxt<'a, 'tcx>,
     body_id: LocalDefId,
 ) -> UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)> {
-    let body = fcx.tcx.hir().maybe_body_owned_by(body_id).expect("body id must have an owner");
+    let body = fcx.tcx.hir_maybe_body_owned_by(body_id).expect("body id must have an owner");
     let mut res = UnordMap::default();
 
     struct UnsafeInferVarsVisitor<'a, 'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 1113f7f7095..ff41a080d62 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -640,7 +640,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let witness = Ty::new_coroutine_witness(self.tcx, expr_def_id.to_def_id(), args);
 
             // Unify `interior` with `witness` and collect all the resulting obligations.
-            let span = self.tcx.hir().body(body_id).value.span;
+            let span = self.tcx.hir_body(body_id).value.span;
             let ty::Infer(ty::InferTy::TyVar(_)) = interior.kind() else {
                 span_bug!(span, "coroutine interior witness not infer: {:?}", interior.kind())
             };
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 77081548d11..7ca44d23e3e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -100,7 +100,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut deferred_asm_checks = self.deferred_asm_checks.borrow_mut();
         debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len());
         for (asm, hir_id) in deferred_asm_checks.drain(..) {
-            let enclosing_id = self.tcx.hir().enclosing_body_owner(hir_id);
+            let enclosing_id = self.tcx.hir_enclosing_body_owner(hir_id);
             let get_operand_ty = |expr| {
                 let ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
                 let ty = self.resolve_vars_if_possible(ty);
@@ -2056,7 +2056,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match node {
             Node::Item(&hir::Item { kind: hir::ItemKind::Fn { body: body_id, .. }, .. })
             | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
-                let body = self.tcx.hir().body(body_id);
+                let body = self.tcx.hir_body(body_id);
                 if let ExprKind::Block(block, _) = &body.value.kind {
                     return Some(block.span);
                 }
@@ -2512,11 +2512,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
-        } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id)
+        } else if let Some(hir::Node::Expr(e)) = self.tcx.hir_get_if_local(def_id)
             && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind
         {
             let param = expected_idx
-                .and_then(|expected_idx| self.tcx.hir().body(*body).params.get(expected_idx));
+                .and_then(|expected_idx| self.tcx.hir_body(*body).params.get(expected_idx));
             let (kind, span) = if let Some(param) = param {
                 // Try to find earlier invocations of this closure to find if the type mismatch
                 // is because of inference. If we find one, point at them.
@@ -2650,7 +2650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         is_method: bool,
     ) -> Option<(IndexVec<ExpectedIdx, (Option<GenericIdx>, FnParam<'_>)>, &hir::Generics<'_>)>
     {
-        let (sig, generics, body_id, param_names) = match self.tcx.hir().get_if_local(def_id)? {
+        let (sig, generics, body_id, param_names) = match self.tcx.hir_get_if_local(def_id)? {
             hir::Node::TraitItem(&hir::TraitItem {
                 generics,
                 kind: hir::TraitItemKind::Fn(sig, trait_fn),
@@ -2695,7 +2695,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match (body_id, param_names) {
             (Some(_), Some(_)) | (None, None) => unreachable!(),
             (Some(body), None) => {
-                let params = self.tcx.hir().body(body).params;
+                let params = self.tcx.hir_body(body).params;
                 let params =
                     params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?;
                 debug_assert_eq!(params.len(), fn_inputs.len());
@@ -2725,8 +2725,8 @@ struct FindClosureArg<'tcx> {
 impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> {
     type NestedFilter = rustc_middle::hir::nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index b77e6de52ff..42236ac6d80 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -290,7 +290,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
         _: Ident,
     ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
         let tcx = self.tcx;
-        let item_def_id = tcx.hir().ty_param_owner(def_id);
+        let item_def_id = tcx.hir_ty_param_owner(def_id);
         let generics = tcx.generics_of(item_def_id);
         let index = generics.param_def_id_to_index[&def_id.to_def_id()];
         // HACK(eddyb) should get the original `Span`.
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 4ec8d0b1f60..347a6557c2a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1811,9 +1811,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     "`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
                 ),
             );
-            let owner = self.tcx.hir().enclosing_body_owner(expr.hir_id);
+            let owner = self.tcx.hir_enclosing_body_owner(expr.hir_id);
             if let ty::Param(param) = expected_ty.kind()
-                && let Some(generics) = self.tcx.hir().get_generics(owner)
+                && let Some(generics) = self.tcx.hir_get_generics(owner)
             {
                 suggest_constraining_type_params(
                     self.tcx,
@@ -1933,7 +1933,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ..
                     } = init
                 {
-                    let hir::Body { value: body_expr, .. } = self.tcx.hir().body(*body_id);
+                    let hir::Body { value: body_expr, .. } = self.tcx.hir_body(*body_id);
                     self.note_type_is_not_clone_inner_expr(body_expr)
                 } else {
                     expr
@@ -2094,9 +2094,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'tcx>,
         expected: Ty<'tcx>,
     ) -> bool {
-        let hir = self.tcx.hir();
+        let tcx = self.tcx;
+        let hir = tcx.hir();
         let enclosing_scope =
-            hir.get_enclosing_scope(expr.hir_id).map(|hir_id| self.tcx.hir_node(hir_id));
+            hir.get_enclosing_scope(expr.hir_id).map(|hir_id| tcx.hir_node(hir_id));
 
         // Get tail expr of the enclosing block or body
         let tail_expr = if let Some(Node::Block(hir::Block { expr, .. })) = enclosing_scope
@@ -2104,8 +2105,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         {
             *expr
         } else {
-            let body_def_id = hir.enclosing_body_owner(expr.hir_id);
-            let body = hir.body_owned_by(body_def_id);
+            let body_def_id = tcx.hir_enclosing_body_owner(expr.hir_id);
+            let body = tcx.hir_body_owned_by(body_def_id);
 
             // Get tail expr of the body
             match body.value.kind {
@@ -2147,7 +2148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ("consider returning a value here", format!("`{expected}` value"))
             };
 
-            let src_map = self.tcx.sess.source_map();
+            let src_map = tcx.sess.source_map();
             let suggestion = if src_map.is_multiline(expr.span) {
                 let indentation = src_map.indentation_before(span).unwrap_or_else(String::new);
                 format!("\n{indentation}/* {suggestion} */")
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 02fbd46173c..9d5184acb3c 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -123,7 +123,7 @@ fn typeck_with_inspect<'tcx>(
     let body_id = node.body_id().unwrap_or_else(|| {
         span_bug!(span, "can't type-check body of {:?}", def_id);
     });
-    let body = tcx.hir().body(body_id);
+    let body = tcx.hir_body(body_id);
 
     let param_env = tcx.param_env(def_id);
 
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 6c4ad65be6a..780ab8c1833 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -531,7 +531,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let hir::def::Res::Local(recv_id) = path.res
             && let Some(segment) = path.segments.first()
         {
-            let body = self.tcx.hir().body_owned_by(self.body_id);
+            let body = self.tcx.hir_body_owned_by(self.body_id);
 
             if let Node::Expr(call_expr) = self.tcx.parent_hir_node(rcvr.hir_id) {
                 let mut let_visitor = LetVisitor {
@@ -1091,7 +1091,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     continue;
                 }
 
-                match self.tcx.hir().get_if_local(item_def_id) {
+                match self.tcx.hir_get_if_local(item_def_id) {
                     // Unmet obligation comes from a `derive` macro, point at it once to
                     // avoid multiple span labels pointing at the same place.
                     Some(Node::Item(hir::Item {
@@ -2599,7 +2599,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             seg1.ident.span,
             StashKey::CallAssocMethod,
             |err| {
-                let body = self.tcx.hir().body_owned_by(self.body_id);
+                let body = self.tcx.hir_body_owned_by(self.body_id);
                 struct LetVisitor {
                     ident_name: Symbol,
                 }
@@ -3336,7 +3336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let accessible_sugg = sugg(accessible_candidates, true);
         let inaccessible_sugg = sugg(inaccessible_candidates, false);
 
-        let (module, _, _) = self.tcx.hir().get_module(scope);
+        let (module, _, _) = self.tcx.hir_get_module(scope);
         let span = module.spans.inject_use_span;
         handle_candidates(accessible_sugg, inaccessible_sugg, span);
     }
@@ -3753,19 +3753,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                         hir::TraitFn::Required([ident, ..]) => {
                                             ident.name == kw::SelfLower
                                         }
-                                        hir::TraitFn::Provided(body_id) => self
-                                            .tcx
-                                            .hir()
-                                            .body(*body_id)
-                                            .params
-                                            .first()
-                                            .is_some_and(|param| {
-                                                matches!(
-                                                    param.pat.kind,
-                                                    hir::PatKind::Binding(_, _, ident, _)
-                                                        if ident.name == kw::SelfLower
-                                                )
-                                            }),
+                                        hir::TraitFn::Provided(body_id) => {
+                                            self.tcx.hir_body(*body_id).params.first().is_some_and(
+                                                |param| {
+                                                    matches!(
+                                                        param.pat.kind,
+                                                        hir::PatKind::Binding(_, _, ident, _)
+                                                            if ident.name == kw::SelfLower
+                                                    )
+                                                },
+                                            )
+                                        }
                                         _ => false,
                                     };
 
@@ -3833,20 +3831,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let Some(param) = param_type {
                 let generics = self.tcx.generics_of(self.body_id.to_def_id());
                 let type_param = generics.type_param(param, self.tcx);
-                let hir = self.tcx.hir();
+                let tcx = self.tcx;
                 if let Some(def_id) = type_param.def_id.as_local() {
-                    let id = self.tcx.local_def_id_to_hir_id(def_id);
+                    let id = tcx.local_def_id_to_hir_id(def_id);
                     // Get the `hir::Param` to verify whether it already has any bounds.
                     // We do this to avoid suggesting code that ends up as `T: FooBar`,
                     // instead we suggest `T: Foo + Bar` in that case.
-                    match self.tcx.hir_node(id) {
+                    match tcx.hir_node(id) {
                         Node::GenericParam(param) => {
                             enum Introducer {
                                 Plus,
                                 Colon,
                                 Nothing,
                             }
-                            let hir_generics = hir.get_generics(id.owner.def_id).unwrap();
+                            let hir_generics = tcx.hir_get_generics(id.owner.def_id).unwrap();
                             let trait_def_ids: DefIdSet = hir_generics
                                 .bounds_for_param(def_id)
                                 .flat_map(|bp| bp.bounds.iter())
@@ -3866,8 +3864,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             let candidate_strs: Vec<_> = candidates
                                 .iter()
                                 .map(|cand| {
-                                    let cand_path = self.tcx.def_path_str(cand.def_id);
-                                    let cand_params = &self.tcx.generics_of(cand.def_id).own_params;
+                                    let cand_path = tcx.def_path_str(cand.def_id);
+                                    let cand_params = &tcx.generics_of(cand.def_id).own_params;
                                     let cand_args: String = cand_params
                                         .iter()
                                         .skip(1)
@@ -3960,9 +3958,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             err.span_suggestions(
                                 sp,
                                 message(format!("add {article} supertrait for")),
-                                candidates.iter().map(|t| {
-                                    format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
-                                }),
+                                candidates
+                                    .iter()
+                                    .map(|t| format!("{} {}", sep, tcx.def_path_str(t.def_id),)),
                                 Applicability::MaybeIncorrect,
                             );
                             return;
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index c5c11c2bd25..ae00bb4e218 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1231,7 +1231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ident: Ident,
     ) -> bool {
         match opt_def_id {
-            Some(def_id) => match self.tcx.hir().get_if_local(def_id) {
+            Some(def_id) => match self.tcx.hir_get_if_local(def_id) {
                 Some(hir::Node::Item(hir::Item {
                     kind: hir::ItemKind::Const(_, _, body_id),
                     ..
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index b54e430a9d9..762d04fdedd 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -143,7 +143,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         match expr.kind {
             hir::ExprKind::Closure(&hir::Closure { capture_clause, body: body_id, .. }) => {
-                let body = self.fcx.tcx.hir().body(body_id);
+                let body = self.fcx.tcx.hir_body(body_id);
                 self.visit_body(body);
                 self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause);
             }
@@ -154,7 +154,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
     }
 
     fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
-        let body = self.fcx.tcx.hir().body(c.body);
+        let body = self.fcx.tcx.hir_body(c.body);
         self.visit_body(body);
     }
 }
@@ -196,7 +196,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let args = self.resolve_vars_if_possible(args);
         let closure_def_id = closure_def_id.expect_local();
 
-        assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id);
+        assert_eq!(self.tcx.hir_body_owner_def_id(body.id()), closure_def_id);
         let mut delegate = InferBorrowKind {
             closure_def_id,
             capture_information: Default::default(),
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 1bf5b19d68d..8c50cc59c1d 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -38,7 +38,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         body: &'tcx hir::Body<'tcx>,
     ) -> &'tcx ty::TypeckResults<'tcx> {
-        let item_def_id = self.tcx.hir().body_owner_def_id(body.id());
+        let item_def_id = self.tcx.hir_body_owner_def_id(body.id());
 
         // This attribute causes us to dump some writeback information
         // in the form of errors, which is used for unit tests.
@@ -49,7 +49,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             wbcx.visit_node_id(param.pat.span, param.hir_id);
         }
         // Type only exists for constants and statics, not functions.
-        match self.tcx.hir().body_owner_kind(item_def_id) {
+        match self.tcx.hir_body_owner_kind(item_def_id) {
             hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => {
                 let item_hir_id = self.tcx.local_def_id_to_hir_id(item_def_id);
                 wbcx.visit_node_id(body.value.span, item_hir_id);
@@ -249,7 +249,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
     fn visit_const_block(&mut self, span: Span, anon_const: &hir::ConstBlock) {
         self.visit_node_id(span, anon_const.hir_id);
 
-        let body = self.tcx().hir().body(anon_const.body);
+        let body = self.tcx().hir_body(anon_const.body);
         self.visit_body(body);
     }
 }
@@ -266,7 +266,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
     fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
         match e.kind {
             hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
-                let body = self.fcx.tcx.hir().body(body);
+                let body = self.fcx.tcx.hir_body(body);
                 for param in body.params {
                     self.visit_node_id(e.span, param.hir_id);
                 }
@@ -790,7 +790,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
             self.fcx
                 .err_ctxt()
                 .emit_inference_failure_err(
-                    self.fcx.tcx.hir().body_owner_def_id(self.body.id()),
+                    self.fcx.tcx.hir_body_owner_def_id(self.body.id()),
                     self.span.to_span(self.fcx.tcx),
                     p.into(),
                     TypeAnnotationNeeded::E0282,
@@ -814,7 +814,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
         // expect that types that show up in the typeck are fully
         // normalized.
         let mut value = if self.should_normalize {
-            let body_id = tcx.hir().body_owner_def_id(self.body.id());
+            let body_id = tcx.hir_body_owner_def_id(self.body.id());
             let cause = ObligationCause::misc(self.span.to_span(tcx), body_id);
             let at = self.fcx.at(&cause, self.fcx.param_env);
             let universes = vec![None; outer_exclusive_binder(value).as_usize()];
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index 569034954c3..d4407559202 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -76,7 +76,7 @@ pub(crate) fn assert_dep_graph(tcx: TyCtxt<'_>) {
             let mut visitor =
                 IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] };
             visitor.process_attrs(CRATE_DEF_ID);
-            tcx.hir().visit_all_item_likes_in_crate(&mut visitor);
+            tcx.hir_visit_all_item_likes_in_crate(&mut visitor);
             (visitor.if_this_changed, visitor.then_this_would_need)
         };
 
@@ -174,8 +174,8 @@ impl<'tcx> IfThisChanged<'tcx> {
 impl<'tcx> Visitor<'tcx> for IfThisChanged<'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 30590bf5d3c..118a6fed036 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -166,7 +166,7 @@ pub(crate) fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
         }
 
         let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
-        tcx.hir().walk_attributes(&mut all_attrs);
+        tcx.hir_walk_attributes(&mut all_attrs);
 
         // Note that we cannot use the existing "unused attribute"-infrastructure
         // here, since that is running before codegen. This is also the reason why
@@ -455,8 +455,8 @@ impl<'tcx> FindAllAttrs<'tcx> {
 impl<'tcx> intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_attribute(&mut self, attr: &'tcx Attribute) {
diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl
index 43c69c8e571..adc7ed54e14 100644
--- a/compiler/rustc_interface/messages.ftl
+++ b/compiler/rustc_interface/messages.ftl
@@ -33,6 +33,10 @@ interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag
 interface_input_file_would_be_overwritten =
     the input file "{$path}" would be overwritten by the generated executable
 
+interface_limit_invalid =
+    `limit` must be a non-negative integer
+    .label = {$error_str}
+
 interface_mixed_bin_crate =
     cannot mix `bin` crate type with others
 
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index c3b858d4f2e..ca4e556dcdb 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -127,3 +127,13 @@ pub(crate) struct AbiRequiredTargetFeature<'a> {
     pub feature: &'a str,
     pub enabled: &'a str,
 }
+
+#[derive(Diagnostic)]
+#[diag(interface_limit_invalid)]
+pub(crate) struct LimitInvalid<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub value_span: Span,
+    pub error_str: &'a str,
+}
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index a2a29612e48..54cd341698f 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -10,6 +10,7 @@
 mod callbacks;
 pub mod errors;
 pub mod interface;
+mod limits;
 pub mod passes;
 mod proc_macro_decls;
 mod queries;
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_interface/src/limits.rs
index 8a367a947d1..8f01edec09f 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_interface/src/limits.rs
@@ -1,61 +1,58 @@
 //! Registering limits:
-//! * recursion_limit,
-//! * move_size_limit, and
-//! * type_length_limit
+//! - recursion_limit: there are various parts of the compiler that must impose arbitrary limits
+//!   on how deeply they recurse to prevent stack overflow.
+//! - move_size_limit
+//! - type_length_limit
+//! - pattern_complexity_limit
 //!
-//! There are various parts of the compiler that must impose arbitrary limits
-//! on how deeply they recurse to prevent stack overflow. Users can override
-//! this via an attribute on the crate like `#![recursion_limit="22"]`. This pass
-//! just peeks and looks for that attribute.
+//! Users can override these limits via an attribute on the crate like
+//! `#![recursion_limit="22"]`. This pass just looks for those attributes.
 
 use std::num::IntErrorKind;
 
 use rustc_ast::attr::AttributeExt;
+use rustc_middle::bug;
+use rustc_middle::query::Providers;
 use rustc_session::{Limit, Limits, Session};
 use rustc_span::{Symbol, sym};
 
-use crate::error::LimitInvalid;
-use crate::query::Providers;
+use crate::errors::LimitInvalid;
 
-pub fn provide(providers: &mut Providers) {
+pub(crate) fn provide(providers: &mut Providers) {
     providers.limits = |tcx, ()| Limits {
-        recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess),
+        recursion_limit: get_recursion_limit(tcx.hir_krate_attrs(), tcx.sess),
         move_size_limit: get_limit(
-            tcx.hir().krate_attrs(),
+            tcx.hir_krate_attrs(),
             tcx.sess,
             sym::move_size_limit,
-            tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0),
+            Limit::new(tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0)),
         ),
         type_length_limit: get_limit(
-            tcx.hir().krate_attrs(),
+            tcx.hir_krate_attrs(),
             tcx.sess,
             sym::type_length_limit,
-            2usize.pow(24),
+            Limit::new(2usize.pow(24)),
+        ),
+        pattern_complexity_limit: get_limit(
+            tcx.hir_krate_attrs(),
+            tcx.sess,
+            sym::pattern_complexity_limit,
+            Limit::unlimited(),
         ),
     }
 }
 
-pub fn get_recursion_limit(krate_attrs: &[impl AttributeExt], sess: &Session) -> Limit {
-    get_limit(krate_attrs, sess, sym::recursion_limit, 128)
+// This one is separate because it must be read prior to macro expansion.
+pub(crate) fn get_recursion_limit(krate_attrs: &[impl AttributeExt], sess: &Session) -> Limit {
+    get_limit(krate_attrs, sess, sym::recursion_limit, Limit::new(128))
 }
 
 fn get_limit(
     krate_attrs: &[impl AttributeExt],
     sess: &Session,
     name: Symbol,
-    default: usize,
+    default: Limit,
 ) -> Limit {
-    match get_limit_size(krate_attrs, sess, name) {
-        Some(size) => Limit::new(size),
-        None => Limit::new(default),
-    }
-}
-
-pub fn get_limit_size(
-    krate_attrs: &[impl AttributeExt],
-    sess: &Session,
-    name: Symbol,
-) -> Option<usize> {
     for attr in krate_attrs {
         if !attr.has_name(name) {
             continue;
@@ -63,7 +60,7 @@ pub fn get_limit_size(
 
         if let Some(sym) = attr.value_str() {
             match sym.as_str().parse() {
-                Ok(n) => return Some(n),
+                Ok(n) => return Limit::new(n),
                 Err(e) => {
                     let error_str = match e.kind() {
                         IntErrorKind::PosOverflow => "`limit` is too large",
@@ -84,5 +81,5 @@ pub fn get_limit_size(
             }
         }
     }
-    None
+    default
 }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index fcebca3ecc9..d70d9d344b9 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -39,7 +39,7 @@ use rustc_trait_selection::traits;
 use tracing::{info, instrument};
 
 use crate::interface::Compiler;
-use crate::{errors, proc_macro_decls, util};
+use crate::{errors, limits, proc_macro_decls, util};
 
 pub fn parse<'a>(sess: &'a Session) -> ast::Crate {
     let krate = sess
@@ -687,6 +687,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
         |tcx, _| tcx.arena.alloc_from_iter(tcx.resolutions(()).stripped_cfg_items.steal());
     providers.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1;
     providers.early_lint_checks = early_lint_checks;
+    limits::provide(providers);
     proc_macro_decls::provide(providers);
     rustc_const_eval::provide(providers);
     rustc_middle::hir::provide(providers);
@@ -845,7 +846,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
                 CStore::from_tcx(tcx).report_unused_deps(tcx);
             },
             {
-                tcx.hir().par_for_each_module(|module| {
+                tcx.par_hir_for_each_module(|module| {
                     tcx.ensure_ok().check_mod_loops(module);
                     tcx.ensure_ok().check_mod_attrs(module);
                     tcx.ensure_ok().check_mod_naked_functions(module);
@@ -870,7 +871,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
 
     rustc_hir_analysis::check_crate(tcx);
     sess.time("MIR_coroutine_by_move_body", || {
-        tcx.hir().par_body_owners(|def_id| {
+        tcx.par_hir_body_owners(|def_id| {
             if tcx.needs_coroutine_by_move_body_def_id(def_id.to_def_id()) {
                 tcx.ensure_done().coroutine_by_move_body_def_id(def_id);
             }
@@ -884,7 +885,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
     tcx.untracked().definitions.freeze();
 
     sess.time("MIR_borrow_checking", || {
-        tcx.hir().par_body_owners(|def_id| {
+        tcx.par_hir_body_owners(|def_id| {
             // Run unsafety check because it's responsible for stealing and
             // deallocating THIR.
             tcx.ensure_ok().check_unsafety(def_id);
@@ -892,21 +893,21 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
         });
     });
     sess.time("MIR_effect_checking", || {
-        tcx.hir().par_body_owners(|def_id| {
+        tcx.par_hir_body_owners(|def_id| {
             tcx.ensure_ok().has_ffi_unwind_calls(def_id);
 
             // If we need to codegen, ensure that we emit all errors from
             // `mir_drops_elaborated_and_const_checked` now, to avoid discovering
             // them later during codegen.
             if tcx.sess.opts.output_types.should_codegen()
-                || tcx.hir().body_const_context(def_id).is_some()
+                || tcx.hir_body_const_context(def_id).is_some()
             {
                 tcx.ensure_ok().mir_drops_elaborated_and_const_checked(def_id);
             }
         });
     });
     sess.time("coroutine_obligations", || {
-        tcx.hir().par_body_owners(|def_id| {
+        tcx.par_hir_body_owners(|def_id| {
             if tcx.is_coroutine(def_id.to_def_id()) {
                 tcx.ensure_ok().mir_coroutine_witnesses(def_id);
                 tcx.ensure_ok().check_coroutine_obligations(
@@ -930,7 +931,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
     // that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts.
     if tcx.sess.opts.unstable_opts.validate_mir {
         sess.time("ensuring_final_MIR_is_computable", || {
-            tcx.hir().par_body_owners(|def_id| {
+            tcx.par_hir_body_owners(|def_id| {
                 tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
             });
         });
@@ -966,7 +967,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
                         tcx.ensure_ok().check_private_in_public(());
                     },
                     {
-                        tcx.hir().par_for_each_module(|module| {
+                        tcx.par_hir_for_each_module(|module| {
                             tcx.ensure_ok().check_mod_deathness(module)
                         });
                     },
@@ -982,7 +983,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
             },
             {
                 sess.time("privacy_checking_modules", || {
-                    tcx.hir().par_for_each_module(|module| {
+                    tcx.par_hir_for_each_module(|module| {
                         tcx.ensure_ok().check_mod_privacy(module);
                     });
                 });
@@ -1134,7 +1135,7 @@ fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit
     // because that would require expanding this while in the middle of expansion, which needs to
     // know the limit before expanding.
     let _ = validate_and_find_value_str_builtin_attr(sym::recursion_limit, sess, krate_attrs);
-    rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess)
+    crate::limits::get_recursion_limit(krate_attrs, sess)
 }
 
 /// Validate *all* occurrences of the given "[value-str]" built-in attribute and return the first find.
diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs
index 82593dbc2b7..00600abb5f1 100644
--- a/compiler/rustc_interface/src/proc_macro_decls.rs
+++ b/compiler/rustc_interface/src/proc_macro_decls.rs
@@ -7,7 +7,7 @@ use rustc_span::sym;
 fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
     let mut decls = None;
 
-    for id in tcx.hir().items() {
+    for id in tcx.hir_free_items() {
         let attrs = tcx.hir().attrs(id.hir_id());
         if attr::contains_name(attrs, sym::rustc_proc_macro_decls) {
             decls = Some(id.owner_id.def_id);
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 480d97e377a..dbe24c9cdf2 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -439,11 +439,11 @@ lint_invalid_crate_type_value = invalid `crate_type` value
     .suggestion = did you mean
 
 # FIXME: we should ordinalize $valid_up_to when we add support for doing so
-lint_invalid_from_utf8_checked = calls to `{$method}` with a invalid literal always return an error
+lint_invalid_from_utf8_checked = calls to `{$method}` with an invalid literal always return an error
     .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes
 
 # FIXME: we should ordinalize $valid_up_to when we add support for doing so
-lint_invalid_from_utf8_unchecked = calls to `{$method}` with a invalid literal are undefined behavior
+lint_invalid_from_utf8_unchecked = calls to `{$method}` with an invalid literal are undefined behavior
     .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes
 
 lint_invalid_nan_comparisons_eq_ne = incorrect NaN comparison, NaN cannot be directly compared to itself
diff --git a/compiler/rustc_lint/src/async_closures.rs b/compiler/rustc_lint/src/async_closures.rs
index 5d40b8ab2ee..02fb22bf782 100644
--- a/compiler/rustc_lint/src/async_closures.rs
+++ b/compiler/rustc_lint/src/async_closures.rs
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncClosureUsage {
             return;
         };
 
-        let mut body = cx.tcx.hir().body(body).value;
+        let mut body = cx.tcx.hir_body(body).value;
 
         // Only peel blocks that have no expressions.
         while let hir::ExprKind::Block(&hir::Block { stmts: [], expr: Some(tail), .. }, None) =
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index ecd40a52e75..e449f110613 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1057,7 +1057,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                             check_no_mangle_on_generic_fn(
                                 no_mangle_attr,
                                 Some(generics),
-                                cx.tcx.hir().get_generics(it.id.owner_id.def_id).unwrap(),
+                                cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(),
                                 it.span,
                             );
                         }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index a67b404e6e1..c74158102c7 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -928,7 +928,7 @@ impl<'tcx> LateContext<'tcx> {
         while let hir::ExprKind::Path(ref qpath) = expr.kind
             && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
                 Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
-                Res::Def(_, def_id) => self.tcx.hir().get_if_local(def_id),
+                Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
                 _ => None,
             }
             && let Some(init) = match parent_node {
@@ -936,7 +936,7 @@ impl<'tcx> LateContext<'tcx> {
                 hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init,
                 hir::Node::Item(item) => match item.kind {
                     hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
-                        Some(self.tcx.hir().body(body_id).value)
+                        Some(self.tcx.hir_body(body_id).value)
                     }
                     _ => None,
                 },
diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs
index bae9defa687..59e38a882dd 100644
--- a/compiler/rustc_lint/src/default_could_be_derived.rs
+++ b/compiler/rustc_lint/src/default_could_be_derived.rs
@@ -76,10 +76,8 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
 
         // We now know we have a manually written definition of a `<Type as Default>::default()`.
 
-        let hir = cx.tcx.hir();
-
         let type_def_id = def.did();
-        let body = hir.body(body_id);
+        let body = cx.tcx.hir_body(body_id);
 
         // FIXME: evaluate bodies with statements and evaluate bindings to see if they would be
         // derivable.
@@ -92,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
         // Keep a mapping of field name to `hir::FieldDef` for every field in the type. We'll use
         // these to check for things like checking whether it has a default or using its span for
         // suggestions.
-        let orig_fields = match hir.get_if_local(type_def_id) {
+        let orig_fields = match cx.tcx.hir_get_if_local(type_def_id) {
             Some(hir::Node::Item(hir::Item {
                 kind:
                     hir::ItemKind::Struct(hir::VariantData::Struct { fields, recovered: _ }, _generics),
@@ -183,7 +181,7 @@ fn mk_lint(
     if removed_all_fields {
         let msg = "to avoid divergence in behavior between `Struct { .. }` and \
                    `<Struct as Default>::default()`, derive the `Default`";
-        if let Some(hir::Node::Item(impl_)) = tcx.hir().get_if_local(impl_def_id) {
+        if let Some(hir::Node::Item(impl_)) = tcx.hir_get_if_local(impl_def_id) {
             diag.multipart_suggestion_verbose(
                 msg,
                 vec![
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index 0a5c52d65ec..757fc1f58bd 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -155,7 +155,7 @@ fn suggest_question_mark<'tcx>(
     // Check that the function/closure/constant we are in has a `Result` type.
     // Otherwise suggesting using `?` may not be a good idea.
     {
-        let ty = cx.typeck_results().expr_ty(cx.tcx.hir().body(body_id).value);
+        let ty = cx.typeck_results().expr_ty(cx.tcx.hir_body(body_id).value);
         let ty::Adt(ret_adt, ..) = ty.kind() else { return false };
         if !cx.tcx.is_diagnostic_item(sym::Result, ret_adt.did()) {
             return false;
@@ -166,7 +166,7 @@ fn suggest_question_mark<'tcx>(
     let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env());
     let ocx = ObligationCtxt::new(&infcx);
 
-    let body_def_id = cx.tcx.hir().body_owner_def_id(body_id);
+    let body_def_id = cx.tcx.hir_body_owner_def_id(body_id);
     let cause =
         ObligationCause::new(span, body_def_id, rustc_infer::traits::ObligationCauseCode::Misc);
 
diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs
index 0081374922e..11eb079ddc0 100644
--- a/compiler/rustc_lint/src/invalid_from_utf8.rs
+++ b/compiler/rustc_lint/src/invalid_from_utf8.rs
@@ -70,12 +70,20 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 {
                 sym::str_from_utf8_mut,
                 sym::str_from_utf8_unchecked,
                 sym::str_from_utf8_unchecked_mut,
+                sym::str_inherent_from_utf8,
+                sym::str_inherent_from_utf8_mut,
+                sym::str_inherent_from_utf8_unchecked,
+                sym::str_inherent_from_utf8_unchecked_mut,
             ]
             .contains(&diag_item)
         {
             let lint = |label, utf8_error: Utf8Error| {
                 let method = diag_item.as_str().strip_prefix("str_").unwrap();
-                let method = format!("std::str::{method}");
+                let method = if let Some(method) = method.strip_prefix("inherent_") {
+                    format!("str::{method}")
+                } else {
+                    format!("std::str::{method}")
+                };
                 let valid_up_to = utf8_error.valid_up_to();
                 let is_unchecked_variant = diag_item.as_str().contains("unchecked");
 
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 3ee908ba9bf..d22515d62d6 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -84,8 +84,8 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
     /// Because lints are scoped lexically, we want to walk nested
     /// items in the context of the outer item, so enable
     /// deep-walking.
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.context.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.context.tcx
     }
 
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
@@ -99,7 +99,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
             self.context.cached_typeck_results.set(None);
         }
 
-        let body = self.context.tcx.hir().body(body_id);
+        let body = self.context.tcx.hir_body(body_id);
         self.visit_body(body);
         self.context.enclosing_body = old_enclosing_body;
 
@@ -191,7 +191,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
         // in order for `check_fn` to be able to use them.
         let old_enclosing_body = self.context.enclosing_body.replace(body_id);
         let old_cached_typeck_results = self.context.cached_typeck_results.take();
-        let body = self.context.tcx.hir().body(body_id);
+        let body = self.context.tcx.hir_body(body_id);
         lint_callback!(self, check_fn, fk, decl, body, span, id);
         hir_visit::walk_fn(self, fk, decl, body_id, id);
         self.context.enclosing_body = old_enclosing_body;
@@ -379,7 +379,7 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
 ) {
     let mut cx = LateContextAndPass { context, pass };
 
-    let (module, _span, hir_id) = tcx.hir().get_module(module_def_id);
+    let (module, _span, hir_id) = tcx.hir_get_module(module_def_id);
 
     cx.with_lint_attrs(hir_id, |cx| {
         // There is no module lint that will have the crate itself as an item, so check it here.
@@ -445,7 +445,7 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>(
         // Since the root module isn't visited as an item (because it isn't an
         // item), warn for it here.
         lint_callback!(cx, check_crate,);
-        tcx.hir().walk_toplevel_module(cx);
+        tcx.hir_walk_toplevel_module(cx);
         lint_callback!(cx, check_crate_post,);
     })
 }
@@ -462,7 +462,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) {
         || {
             tcx.sess.time("module_lints", || {
                 // Run per-module lints
-                tcx.hir().par_for_each_module(|module| tcx.ensure_ok().lint_mod(module));
+                tcx.par_hir_for_each_module(|module| tcx.ensure_ok().lint_mod(module));
             });
         },
     );
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 5a4ed68440a..4ede9b44087 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -144,7 +144,7 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
 
     let mut visitor = LintLevelMaximum { tcx, dont_need_to_run };
     visitor.process_opts();
-    tcx.hir().walk_attributes(&mut visitor);
+    tcx.hir_walk_attributes(&mut visitor);
 
     visitor.dont_need_to_run
 }
@@ -270,8 +270,8 @@ impl<'tcx> LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
 impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.provider.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.provider.tcx
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
@@ -365,8 +365,8 @@ impl<'tcx> LintLevelMaximum<'tcx> {
 impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     /// FIXME(blyxyas): In a future revision, we should also graph #![allow]s,
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index a6b2384f2d7..7eb11f9e608 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -22,6 +22,7 @@
 #include "llvm/Passes/StandardInstrumentations.h"
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Program.h"
 #include "llvm/Support/TimeProfiler.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Target/TargetMachine.h"
@@ -472,16 +473,19 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0');
     auto Arg0 = std::string(ArgsCstrBuff);
     buffer_offset = Arg0.size() + 1;
-    auto ArgsCppStr = std::string(ArgsCstrBuff + buffer_offset,
-                                  ArgsCstrBuffLen - buffer_offset);
-    auto i = 0;
-    while (i != std::string::npos) {
-      i = ArgsCppStr.find('\0', i + 1);
-      if (i != std::string::npos)
-        ArgsCppStr.replace(i, 1, " ");
+
+    std::string CommandlineArgs;
+    raw_string_ostream OS(CommandlineArgs);
+    ListSeparator LS(" ");
+    for (StringRef Arg : split(StringRef(ArgsCstrBuff + buffer_offset,
+                                         ArgsCstrBuffLen - buffer_offset),
+                               '\0')) {
+      OS << LS;
+      sys::printArg(OS, Arg, /*Quote=*/true);
     }
+    OS.flush();
     Options.MCOptions.Argv0 = Arg0;
-    Options.MCOptions.CommandlineArgs = ArgsCppStr;
+    Options.MCOptions.CommandlineArgs = CommandlineArgs;
 #else
     int buffer_offset = 0;
     assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0');
diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs
index 154eb684f11..24689ea61d0 100644
--- a/compiler/rustc_metadata/src/foreign_modules.rs
+++ b/compiler/rustc_metadata/src/foreign_modules.rs
@@ -10,13 +10,13 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> FxIndexMap<Def
     let mut modules = FxIndexMap::default();
 
     // We need to collect all the `ForeignMod`, even if they are empty.
-    for id in tcx.hir().items() {
+    for id in tcx.hir_free_items() {
         if !matches!(tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
             continue;
         }
 
         let def_id = id.owner_id.to_def_id();
-        let item = tcx.hir().item(id);
+        let item = tcx.hir_item(id);
 
         if let hir::ItemKind::ForeignMod { abi, items } = item.kind {
             let foreign_items = items.iter().map(|it| it.id.owner_id.to_def_id()).collect();
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index d8a7c32a299..88a88847e6b 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -696,7 +696,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let target_modifiers = stat!("target-modifiers", || self.encode_target_modifiers());
 
         let root = stat!("final", || {
-            let attrs = tcx.hir().krate_attrs();
+            let attrs = tcx.hir_krate_attrs();
             self.lazy(CrateRoot {
                 header: CrateHeader {
                     name: tcx.crate_name(LOCAL_CRATE),
@@ -1763,7 +1763,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 if should_encode_const(tcx.def_kind(def_id)) {
                     let qualifs = tcx.mir_const_qualif(def_id);
                     record!(self.tables.mir_const_qualif[def_id.to_def_id()] <- qualifs);
-                    let body = tcx.hir().maybe_body_owned_by(def_id);
+                    let body = tcx.hir_maybe_body_owned_by(def_id);
                     if let Some(body) = body {
                         let const_data = rendered_const(self.tcx, &body, def_id);
                         record!(self.tables.rendered_const[def_id.to_def_id()] <- const_data);
@@ -1940,7 +1940,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     bug!("Unknown proc-macro type for item {:?}", id);
                 };
 
-                let mut def_key = self.tcx.hir().def_key(id);
+                let mut def_key = self.tcx.hir_def_key(id);
                 def_key.disambiguated_data.data = DefPathData::MacroNs(name);
 
                 let def_id = id.to_def_id();
@@ -2076,7 +2076,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let mut trait_impls: FxIndexMap<DefId, Vec<(DefIndex, Option<SimplifiedType>)>> =
             FxIndexMap::default();
 
-        for id in tcx.hir().items() {
+        for id in tcx.hir_free_items() {
             let DefKind::Impl { of_trait } = tcx.def_kind(id.owner_id) else {
                 continue;
             };
@@ -2410,7 +2410,6 @@ pub(crate) fn provide(providers: &mut Providers) {
 /// use a different method for pretty-printing. Ideally this function
 /// should only ever be used as a fallback.
 pub fn rendered_const<'tcx>(tcx: TyCtxt<'tcx>, body: &hir::Body<'_>, def_id: LocalDefId) -> String {
-    let hir = tcx.hir();
     let value = body.value;
 
     #[derive(PartialEq, Eq)]
@@ -2467,7 +2466,7 @@ pub fn rendered_const<'tcx>(tcx: TyCtxt<'tcx>, body: &hir::Body<'_>, def_id: Loc
 
         // Otherwise we prefer pretty-printing to get rid of extraneous whitespace, comments and
         // other formatting artifacts.
-        Literal | Simple => id_to_string(&hir, body.id().hir_id),
+        Literal | Simple => id_to_string(&tcx, body.id().hir_id),
 
         // FIXME: Omit the curly braces if the enclosing expression is an array literal
         //        with a repeated element (an `ExprKind::Repeat`) as in such case it
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index de722e62043..1b6a174c093 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -22,6 +22,7 @@ rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
 rustc_graphviz = { path = "../rustc_graphviz" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_index = { path = "../rustc_index" }
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 09c16222be1..0b3c0be1a4e 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -37,9 +37,6 @@ middle_autodiff_unsafe_inner_const_ref = reading from a `Duplicated` const {$ty}
 middle_bounds_check =
     index out of bounds: the length is {$len} but the index is {$index}
 
-middle_cannot_be_normalized =
-    unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
-
 middle_conflict_types =
     this expression supplies two conflicting concrete types for the same opaque type
 
@@ -52,9 +49,6 @@ middle_const_eval_non_int =
 middle_const_not_used_in_type_alias =
     const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias
 
-middle_cycle =
-    a cycle occurred during layout computation
-
 middle_deprecated = use of deprecated {$kind} `{$path}`{$has_note ->
         [true] : {$note}
         *[other] {""}
@@ -78,12 +72,22 @@ middle_erroneous_constant = erroneous constant encountered
 middle_failed_writing_file =
     failed to write file {$path}: {$error}"
 
+middle_layout_cycle =
+    a cycle occurred during layout computation
+
+middle_layout_normalization_failure =
+    unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
+
 middle_layout_references_error =
     the type has an unknown layout
 
-middle_limit_invalid =
-    `limit` must be a non-negative integer
-    .label = {$error_str}
+middle_layout_size_overflow =
+    values of the type `{$ty}` are too big for the target architecture
+
+middle_layout_too_generic = the type `{$ty}` does not have a fixed layout
+
+middle_layout_unknown =
+    the type `{$ty}` has an unknown layout
 
 middle_opaque_hidden_type_mismatch =
     concrete type differs from previous defining opaque type use
@@ -102,16 +106,8 @@ middle_strict_coherence_needs_negative_coherence =
     to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
     .label = due to this attribute
 
-middle_too_generic = `{$ty}` does not have a fixed size
-
 middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
 
-middle_unknown_layout =
-    the type `{$ty}` has an unknown layout
-
 middle_unsupported_union = we don't support unions yet: '{$ty_name}'
 
-middle_values_too_big =
-    values of the type `{$ty}` are too big for the target architecture
-
 middle_written_to_path = the full type name has been written to '{$path}'
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index 91b18295b43..be8a3403ba9 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -68,16 +68,6 @@ pub enum TypeMismatchReason {
 }
 
 #[derive(Diagnostic)]
-#[diag(middle_limit_invalid)]
-pub(crate) struct LimitInvalid<'a> {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub value_span: Span,
-    pub error_str: &'a str,
-}
-
-#[derive(Diagnostic)]
 #[diag(middle_recursion_limit_reached)]
 #[help]
 pub(crate) struct RecursionLimitReached<'tcx> {
@@ -142,19 +132,19 @@ impl fmt::Debug for CustomSubdiagnostic<'_> {
 
 #[derive(Diagnostic)]
 pub enum LayoutError<'tcx> {
-    #[diag(middle_unknown_layout)]
+    #[diag(middle_layout_unknown)]
     Unknown { ty: Ty<'tcx> },
 
-    #[diag(middle_too_generic)]
+    #[diag(middle_layout_too_generic)]
     TooGeneric { ty: Ty<'tcx> },
 
-    #[diag(middle_values_too_big)]
+    #[diag(middle_layout_size_overflow)]
     Overflow { ty: Ty<'tcx> },
 
-    #[diag(middle_cannot_be_normalized)]
+    #[diag(middle_layout_normalization_failure)]
     NormalizationFailure { ty: Ty<'tcx>, failure_ty: String },
 
-    #[diag(middle_cycle)]
+    #[diag(middle_layout_cycle)]
     Cycle,
 
     #[diag(middle_layout_references_error)]
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map.rs
index 83c7bb0f52f..3436c2f372f 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -93,7 +93,7 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> {
             return None;
         }
 
-        let parent_id = self.map.def_key(self.current_id.owner.def_id).parent;
+        let parent_id = self.map.tcx.hir_def_key(self.current_id.owner.def_id).parent;
         let parent_id = parent_id.map_or(CRATE_OWNER_ID, |local_def_index| {
             let def_id = LocalDefId { local_def_index };
             self.map.tcx.local_def_id_to_hir_id(def_id).owner
@@ -164,131 +164,127 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn parent_hir_node(self, hir_id: HirId) -> Node<'tcx> {
         self.hir_node(self.parent_hir_id(hir_id))
     }
-}
-
-impl<'hir> Map<'hir> {
-    #[inline]
-    pub fn krate(self) -> &'hir Crate<'hir> {
-        self.tcx.hir_crate(())
-    }
 
     #[inline]
-    pub fn root_module(self) -> &'hir Mod<'hir> {
-        match self.tcx.hir_owner_node(CRATE_OWNER_ID) {
+    pub fn hir_root_module(self) -> &'tcx Mod<'tcx> {
+        match self.hir_owner_node(CRATE_OWNER_ID) {
             OwnerNode::Crate(item) => item,
             _ => bug!(),
         }
     }
 
     #[inline]
-    pub fn items(self) -> impl Iterator<Item = ItemId> + 'hir {
-        self.tcx.hir_crate_items(()).free_items.iter().copied()
+    pub fn hir_free_items(self) -> impl Iterator<Item = ItemId> + 'tcx {
+        self.hir_crate_items(()).free_items.iter().copied()
     }
 
     #[inline]
-    pub fn module_items(self, module: LocalModDefId) -> impl Iterator<Item = ItemId> + 'hir {
-        self.tcx.hir_module_items(module).free_items()
+    pub fn hir_module_free_items(
+        self,
+        module: LocalModDefId,
+    ) -> impl Iterator<Item = ItemId> + 'tcx {
+        self.hir_module_items(module).free_items()
     }
 
-    pub fn def_key(self, def_id: LocalDefId) -> DefKey {
+    pub fn hir_def_key(self, def_id: LocalDefId) -> DefKey {
         // Accessing the DefKey is ok, since it is part of DefPathHash.
-        self.tcx.definitions_untracked().def_key(def_id)
+        self.definitions_untracked().def_key(def_id)
     }
 
-    pub fn def_path(self, def_id: LocalDefId) -> DefPath {
+    pub fn hir_def_path(self, def_id: LocalDefId) -> DefPath {
         // Accessing the DefPath is ok, since it is part of DefPathHash.
-        self.tcx.definitions_untracked().def_path(def_id)
+        self.definitions_untracked().def_path(def_id)
     }
 
     #[inline]
-    pub fn def_path_hash(self, def_id: LocalDefId) -> DefPathHash {
+    pub fn hir_def_path_hash(self, def_id: LocalDefId) -> DefPathHash {
         // Accessing the DefPathHash is ok, it is incr. comp. stable.
-        self.tcx.definitions_untracked().def_path_hash(def_id)
+        self.definitions_untracked().def_path_hash(def_id)
     }
 
-    pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {
-        id.as_local().map(|id| self.tcx.hir_node_by_def_id(id))
+    pub fn hir_get_if_local(self, id: DefId) -> Option<Node<'tcx>> {
+        id.as_local().map(|id| self.hir_node_by_def_id(id))
     }
 
-    pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
-        self.tcx.opt_hir_owner_node(id)?.generics()
+    pub fn hir_get_generics(self, id: LocalDefId) -> Option<&'tcx Generics<'tcx>> {
+        self.opt_hir_owner_node(id)?.generics()
     }
 
-    pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
-        self.tcx.hir_owner_node(id.owner_id).expect_item()
+    pub fn hir_item(self, id: ItemId) -> &'tcx Item<'tcx> {
+        self.hir_owner_node(id.owner_id).expect_item()
     }
 
-    pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> {
-        self.tcx.hir_owner_node(id.owner_id).expect_trait_item()
+    pub fn hir_trait_item(self, id: TraitItemId) -> &'tcx TraitItem<'tcx> {
+        self.hir_owner_node(id.owner_id).expect_trait_item()
     }
 
-    pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> {
-        self.tcx.hir_owner_node(id.owner_id).expect_impl_item()
+    pub fn hir_impl_item(self, id: ImplItemId) -> &'tcx ImplItem<'tcx> {
+        self.hir_owner_node(id.owner_id).expect_impl_item()
     }
 
-    pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
-        self.tcx.hir_owner_node(id.owner_id).expect_foreign_item()
+    pub fn hir_foreign_item(self, id: ForeignItemId) -> &'tcx ForeignItem<'tcx> {
+        self.hir_owner_node(id.owner_id).expect_foreign_item()
     }
 
-    pub fn body(self, id: BodyId) -> &'hir Body<'hir> {
-        self.tcx.hir_owner_nodes(id.hir_id.owner).bodies[&id.hir_id.local_id]
+    pub fn hir_body(self, id: BodyId) -> &'tcx Body<'tcx> {
+        self.hir_owner_nodes(id.hir_id.owner).bodies[&id.hir_id.local_id]
     }
 
     #[track_caller]
-    pub fn fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
-        self.tcx.hir_node(hir_id).fn_decl()
+    pub fn hir_fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'tcx FnDecl<'tcx>> {
+        self.hir_node(hir_id).fn_decl()
     }
 
     #[track_caller]
-    pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> {
-        self.tcx.hir_node(hir_id).fn_sig()
+    pub fn hir_fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'tcx FnSig<'tcx>> {
+        self.hir_node(hir_id).fn_sig()
     }
 
     #[track_caller]
-    pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId {
-        for (_, node) in self.parent_iter(hir_id) {
+    pub fn hir_enclosing_body_owner(self, hir_id: HirId) -> LocalDefId {
+        for (_, node) in self.hir().parent_iter(hir_id) {
             if let Some((def_id, _)) = node.associated_body() {
                 return def_id;
             }
         }
 
-        bug!("no `enclosing_body_owner` for hir_id `{}`", hir_id);
+        bug!("no `hir_enclosing_body_owner` for hir_id `{}`", hir_id);
     }
 
     /// Returns the `HirId` that corresponds to the definition of
     /// which this is the body of, i.e., a `fn`, `const` or `static`
     /// item (possibly associated), a closure, or a `hir::AnonConst`.
-    pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
-        let parent = self.tcx.parent_hir_id(hir_id);
-        assert_eq!(self.tcx.hir_node(parent).body_id().unwrap().hir_id, hir_id, "{hir_id:?}");
+    pub fn hir_body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
+        let parent = self.parent_hir_id(hir_id);
+        assert_eq!(self.hir_node(parent).body_id().unwrap().hir_id, hir_id, "{hir_id:?}");
         parent
     }
 
-    pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId {
-        self.tcx.parent_hir_node(hir_id).associated_body().unwrap().0
+    pub fn hir_body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId {
+        self.parent_hir_node(hir_id).associated_body().unwrap().0
     }
 
     /// Given a `LocalDefId`, returns the `BodyId` associated with it,
     /// if the node is a body owner, otherwise returns `None`.
-    pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<&'hir Body<'hir>> {
-        Some(self.body(self.tcx.hir_node_by_def_id(id).body_id()?))
+    pub fn hir_maybe_body_owned_by(self, id: LocalDefId) -> Option<&'tcx Body<'tcx>> {
+        Some(self.hir_body(self.hir_node_by_def_id(id).body_id()?))
     }
 
     /// Given a body owner's id, returns the `BodyId` associated with it.
     #[track_caller]
-    pub fn body_owned_by(self, id: LocalDefId) -> &'hir Body<'hir> {
-        self.maybe_body_owned_by(id).unwrap_or_else(|| {
-            let hir_id = self.tcx.local_def_id_to_hir_id(id);
+    pub fn hir_body_owned_by(self, id: LocalDefId) -> &'tcx Body<'tcx> {
+        self.hir_maybe_body_owned_by(id).unwrap_or_else(|| {
+            let hir_id = self.local_def_id_to_hir_id(id);
             span_bug!(
-                self.span(hir_id),
+                self.hir().span(hir_id),
                 "body_owned_by: {} has no associated body",
-                self.node_to_string(hir_id)
+                self.hir().node_to_string(hir_id)
             );
         })
     }
 
-    pub fn body_param_names(self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
-        self.body(id).params.iter().map(|arg| match arg.pat.kind {
+    pub fn hir_body_param_names(self, id: BodyId) -> impl Iterator<Item = Ident> + 'tcx {
+        self.hir_body(id).params.iter().map(|arg| match arg.pat.kind {
             PatKind::Binding(_, _, ident, _) => ident,
             _ => Ident::empty(),
         })
@@ -297,9 +293,9 @@ impl<'hir> Map<'hir> {
     /// Returns the `BodyOwnerKind` of this `LocalDefId`.
     ///
     /// Panics if `LocalDefId` does not have an associated body.
-    pub fn body_owner_kind(self, def_id: impl Into<DefId>) -> BodyOwnerKind {
+    pub fn hir_body_owner_kind(self, def_id: impl Into<DefId>) -> BodyOwnerKind {
         let def_id = def_id.into();
-        match self.tcx.def_kind(def_id) {
+        match self.def_kind(def_id) {
             DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
                 BodyOwnerKind::Const { inline: false }
             }
@@ -320,17 +316,17 @@ impl<'hir> Map<'hir> {
     /// This should only be used for determining the context of a body, a return
     /// value of `Some` does not always suggest that the owner of the body is `const`,
     /// just that it has to be checked as if it were.
-    pub fn body_const_context(self, def_id: impl Into<DefId>) -> Option<ConstContext> {
+    pub fn hir_body_const_context(self, def_id: impl Into<DefId>) -> Option<ConstContext> {
         let def_id = def_id.into();
-        let ccx = match self.body_owner_kind(def_id) {
+        let ccx = match self.hir_body_owner_kind(def_id) {
             BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
             BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability),
 
-            BodyOwnerKind::Fn if self.tcx.is_constructor(def_id) => return None,
-            BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn(def_id) => {
+            BodyOwnerKind::Fn if self.is_constructor(def_id) => return None,
+            BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.is_const_fn(def_id) => {
                 ConstContext::ConstFn
             }
-            BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id) => ConstContext::ConstFn,
+            BodyOwnerKind::Fn if self.is_const_default_method(def_id) => ConstContext::ConstFn,
             BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
         };
 
@@ -341,55 +337,55 @@ impl<'hir> Map<'hir> {
     /// crate. If you would prefer to iterate over the bodies
     /// themselves, you can do `self.hir().krate().body_ids.iter()`.
     #[inline]
-    pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir {
-        self.tcx.hir_crate_items(()).body_owners.iter().copied()
+    pub fn hir_body_owners(self) -> impl Iterator<Item = LocalDefId> + 'tcx {
+        self.hir_crate_items(()).body_owners.iter().copied()
     }
 
     #[inline]
-    pub fn par_body_owners(self, f: impl Fn(LocalDefId) + DynSend + DynSync) {
-        par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id));
+    pub fn par_hir_body_owners(self, f: impl Fn(LocalDefId) + DynSend + DynSync) {
+        par_for_each_in(&self.hir_crate_items(()).body_owners[..], |&def_id| f(def_id));
     }
 
-    pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId {
-        let def_kind = self.tcx.def_kind(def_id);
+    pub fn hir_ty_param_owner(self, def_id: LocalDefId) -> LocalDefId {
+        let def_kind = self.def_kind(def_id);
         match def_kind {
             DefKind::Trait | DefKind::TraitAlias => def_id,
             DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => {
-                self.tcx.local_parent(def_id)
+                self.local_parent(def_id)
             }
             _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind),
         }
     }
 
-    pub fn ty_param_name(self, def_id: LocalDefId) -> Symbol {
-        let def_kind = self.tcx.def_kind(def_id);
+    pub fn hir_ty_param_name(self, def_id: LocalDefId) -> Symbol {
+        let def_kind = self.def_kind(def_id);
         match def_kind {
             DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper,
             DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => {
-                self.tcx.item_name(def_id.to_def_id())
+                self.item_name(def_id.to_def_id())
             }
             _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind),
         }
     }
 
-    pub fn trait_impls(self, trait_did: DefId) -> &'hir [LocalDefId] {
-        self.tcx.all_local_trait_impls(()).get(&trait_did).map_or(&[], |xs| &xs[..])
+    pub fn hir_trait_impls(self, trait_did: DefId) -> &'tcx [LocalDefId] {
+        self.all_local_trait_impls(()).get(&trait_did).map_or(&[], |xs| &xs[..])
     }
 
     /// Gets the attributes on the crate. This is preferable to
     /// invoking `krate.attrs` because it registers a tighter
     /// dep-graph access.
-    pub fn krate_attrs(self) -> &'hir [Attribute] {
-        self.attrs(CRATE_HIR_ID)
+    pub fn hir_krate_attrs(self) -> &'tcx [Attribute] {
+        self.hir().attrs(CRATE_HIR_ID)
     }
 
-    pub fn rustc_coherence_is_core(self) -> bool {
-        self.krate_attrs().iter().any(|attr| attr.has_name(sym::rustc_coherence_is_core))
+    pub fn hir_rustc_coherence_is_core(self) -> bool {
+        self.hir_krate_attrs().iter().any(|attr| attr.has_name(sym::rustc_coherence_is_core))
     }
 
-    pub fn get_module(self, module: LocalModDefId) -> (&'hir Mod<'hir>, Span, HirId) {
+    pub fn hir_get_module(self, module: LocalModDefId) -> (&'tcx Mod<'tcx>, Span, HirId) {
         let hir_id = HirId::make_owner(module.to_local_def_id());
-        match self.tcx.hir_owner_node(hir_id.owner) {
+        match self.hir_owner_node(hir_id.owner) {
             OwnerNode::Item(&Item { span, kind: ItemKind::Mod(m), .. }) => (m, span, hir_id),
             OwnerNode::Crate(item) => (item, item.spans.inner_span, hir_id),
             node => panic!("not a module: {node:?}"),
@@ -397,20 +393,20 @@ impl<'hir> Map<'hir> {
     }
 
     /// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`.
-    pub fn walk_toplevel_module<V>(self, visitor: &mut V) -> V::Result
+    pub fn hir_walk_toplevel_module<V>(self, visitor: &mut V) -> V::Result
     where
-        V: Visitor<'hir>,
+        V: Visitor<'tcx>,
     {
-        let (top_mod, span, hir_id) = self.get_module(LocalModDefId::CRATE_DEF_ID);
+        let (top_mod, span, hir_id) = self.hir_get_module(LocalModDefId::CRATE_DEF_ID);
         visitor.visit_mod(top_mod, span, hir_id)
     }
 
     /// Walks the attributes in a crate.
-    pub fn walk_attributes<V>(self, visitor: &mut V) -> V::Result
+    pub fn hir_walk_attributes<V>(self, visitor: &mut V) -> V::Result
     where
-        V: Visitor<'hir>,
+        V: Visitor<'tcx>,
     {
-        let krate = self.krate();
+        let krate = self.hir_crate(());
         for info in krate.owners.iter() {
             if let MaybeOwner::Owner(info) = info {
                 for attrs in info.attrs.map.values() {
@@ -424,73 +420,87 @@ impl<'hir> Map<'hir> {
     /// Visits all item-likes in the crate in some deterministic (but unspecified) order. If you
     /// need to process every item-like, and don't care about visiting nested items in a particular
     /// order then this method is the best choice. If you do care about this nesting, you should
-    /// use the `tcx.hir().walk_toplevel_module`.
+    /// use the `tcx.hir_walk_toplevel_module`.
     ///
     /// Note that this function will access HIR for all the item-likes in the crate. If you only
     /// need to access some of them, it is usually better to manually loop on the iterators
     /// provided by `tcx.hir_crate_items(())`.
     ///
     /// Please see the notes in `intravisit.rs` for more information.
-    pub fn visit_all_item_likes_in_crate<V>(self, visitor: &mut V) -> V::Result
+    pub fn hir_visit_all_item_likes_in_crate<V>(self, visitor: &mut V) -> V::Result
     where
-        V: Visitor<'hir>,
+        V: Visitor<'tcx>,
     {
-        let krate = self.tcx.hir_crate_items(());
-        walk_list!(visitor, visit_item, krate.free_items().map(|id| self.item(id)));
-        walk_list!(visitor, visit_trait_item, krate.trait_items().map(|id| self.trait_item(id)));
-        walk_list!(visitor, visit_impl_item, krate.impl_items().map(|id| self.impl_item(id)));
+        let krate = self.hir_crate_items(());
+        walk_list!(visitor, visit_item, krate.free_items().map(|id| self.hir_item(id)));
+        walk_list!(
+            visitor,
+            visit_trait_item,
+            krate.trait_items().map(|id| self.hir_trait_item(id))
+        );
+        walk_list!(visitor, visit_impl_item, krate.impl_items().map(|id| self.hir_impl_item(id)));
         walk_list!(
             visitor,
             visit_foreign_item,
-            krate.foreign_items().map(|id| self.foreign_item(id))
+            krate.foreign_items().map(|id| self.hir_foreign_item(id))
         );
         V::Result::output()
     }
 
     /// This method is the equivalent of `visit_all_item_likes_in_crate` but restricted to
     /// item-likes in a single module.
-    pub fn visit_item_likes_in_module<V>(self, module: LocalModDefId, visitor: &mut V) -> V::Result
+    pub fn hir_visit_item_likes_in_module<V>(
+        self,
+        module: LocalModDefId,
+        visitor: &mut V,
+    ) -> V::Result
     where
-        V: Visitor<'hir>,
+        V: Visitor<'tcx>,
     {
-        let module = self.tcx.hir_module_items(module);
-        walk_list!(visitor, visit_item, module.free_items().map(|id| self.item(id)));
-        walk_list!(visitor, visit_trait_item, module.trait_items().map(|id| self.trait_item(id)));
-        walk_list!(visitor, visit_impl_item, module.impl_items().map(|id| self.impl_item(id)));
+        let module = self.hir_module_items(module);
+        walk_list!(visitor, visit_item, module.free_items().map(|id| self.hir_item(id)));
+        walk_list!(
+            visitor,
+            visit_trait_item,
+            module.trait_items().map(|id| self.hir_trait_item(id))
+        );
+        walk_list!(visitor, visit_impl_item, module.impl_items().map(|id| self.hir_impl_item(id)));
         walk_list!(
             visitor,
             visit_foreign_item,
-            module.foreign_items().map(|id| self.foreign_item(id))
+            module.foreign_items().map(|id| self.hir_foreign_item(id))
         );
         V::Result::output()
     }
 
-    pub fn for_each_module(self, mut f: impl FnMut(LocalModDefId)) {
-        let crate_items = self.tcx.hir_crate_items(());
+    pub fn hir_for_each_module(self, mut f: impl FnMut(LocalModDefId)) {
+        let crate_items = self.hir_crate_items(());
         for module in crate_items.submodules.iter() {
             f(LocalModDefId::new_unchecked(module.def_id))
         }
     }
 
     #[inline]
-    pub fn par_for_each_module(self, f: impl Fn(LocalModDefId) + DynSend + DynSync) {
-        let crate_items = self.tcx.hir_crate_items(());
+    pub fn par_hir_for_each_module(self, f: impl Fn(LocalModDefId) + DynSend + DynSync) {
+        let crate_items = self.hir_crate_items(());
         par_for_each_in(&crate_items.submodules[..], |module| {
             f(LocalModDefId::new_unchecked(module.def_id))
         })
     }
 
     #[inline]
-    pub fn try_par_for_each_module(
+    pub fn try_par_hir_for_each_module(
         self,
         f: impl Fn(LocalModDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
     ) -> Result<(), ErrorGuaranteed> {
-        let crate_items = self.tcx.hir_crate_items(());
+        let crate_items = self.hir_crate_items(());
         try_par_for_each_in(&crate_items.submodules[..], |module| {
             f(LocalModDefId::new_unchecked(module.def_id))
         })
     }
+}
 
+impl<'hir> Map<'hir> {
     /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
     /// until the crate root is reached. Prefer this over your own loop using `parent_id`.
     #[inline]
@@ -526,7 +536,7 @@ impl<'hir> Map<'hir> {
     /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
     /// Used exclusively for diagnostics, to avoid suggestion function calls.
     pub fn is_inside_const_context(self, hir_id: HirId) -> bool {
-        self.body_const_context(self.enclosing_body_owner(hir_id)).is_some()
+        self.tcx.hir_body_const_context(self.tcx.hir_enclosing_body_owner(hir_id)).is_some()
     }
 
     /// Retrieves the `HirId` for `id`'s enclosing function *if* the `id` block or return is
@@ -552,7 +562,8 @@ impl<'hir> Map<'hir> {
     /// }
     /// ```
     pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
-        let enclosing_body_owner = self.tcx.local_def_id_to_hir_id(self.enclosing_body_owner(id));
+        let enclosing_body_owner =
+            self.tcx.local_def_id_to_hir_id(self.tcx.hir_enclosing_body_owner(id));
 
         // Return `None` if the `id` expression is not the returned value of the enclosing body
         let mut iter = [id].into_iter().chain(self.parent_id_iter(id)).peekable();
@@ -921,7 +932,7 @@ impl<'hir> Map<'hir> {
             Node::Variant(variant) => variant.span,
             Node::Field(field) => field.span,
             Node::AnonConst(constant) => constant.span,
-            Node::ConstBlock(constant) => self.body(constant.body).value.span,
+            Node::ConstBlock(constant) => self.tcx.hir_body(constant.body).value.span,
             Node::ConstArg(const_arg) => const_arg.span(),
             Node::Expr(expr) => expr.span,
             Node::ExprField(field) => field.span,
@@ -1014,39 +1025,35 @@ impl<'hir> Map<'hir> {
     }
 }
 
-impl<'hir> intravisit::Map<'hir> for Map<'hir> {
-    fn hir_node(&self, hir_id: HirId) -> Node<'hir> {
-        self.tcx.hir_node(hir_id)
-    }
-
-    fn hir_node_by_def_id(&self, def_id: LocalDefId) -> Node<'hir> {
-        self.tcx.hir_node_by_def_id(def_id)
+impl<'tcx> intravisit::HirTyCtxt<'tcx> for TyCtxt<'tcx> {
+    fn hir_node(&self, hir_id: HirId) -> Node<'tcx> {
+        (*self).hir_node(hir_id)
     }
 
-    fn body(&self, id: BodyId) -> &'hir Body<'hir> {
-        (*self).body(id)
+    fn hir_body(&self, id: BodyId) -> &'tcx Body<'tcx> {
+        (*self).hir_body(id)
     }
 
-    fn item(&self, id: ItemId) -> &'hir Item<'hir> {
-        (*self).item(id)
+    fn hir_item(&self, id: ItemId) -> &'tcx Item<'tcx> {
+        (*self).hir_item(id)
     }
 
-    fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
-        (*self).trait_item(id)
+    fn hir_trait_item(&self, id: TraitItemId) -> &'tcx TraitItem<'tcx> {
+        (*self).hir_trait_item(id)
     }
 
-    fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
-        (*self).impl_item(id)
+    fn hir_impl_item(&self, id: ImplItemId) -> &'tcx ImplItem<'tcx> {
+        (*self).hir_impl_item(id)
     }
 
-    fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
-        (*self).foreign_item(id)
+    fn hir_foreign_item(&self, id: ForeignItemId) -> &'tcx ForeignItem<'tcx> {
+        (*self).hir_foreign_item(id)
     }
 }
 
 impl<'tcx> pprust_hir::PpAnn for TyCtxt<'tcx> {
     fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
-        pprust_hir::PpAnn::nested(&(&self.hir() as &dyn intravisit::Map<'_>), state, nested)
+        pprust_hir::PpAnn::nested(&(self as &dyn intravisit::HirTyCtxt<'_>), state, nested)
     }
 }
 
@@ -1239,7 +1246,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
 pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> ModuleItems {
     let mut collector = ItemCollector::new(tcx, false);
 
-    let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id);
+    let (hir_mod, span, hir_id) = tcx.hir_get_module(module_id);
     collector.visit_mod(hir_mod, span, hir_id);
 
     let ItemCollector {
@@ -1272,7 +1279,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
     // module item (the former starts at the crate root) but only
     // the former needs to collect it. ItemCollector does not do this for us.
     collector.submodules.push(CRATE_OWNER_ID);
-    tcx.hir().walk_toplevel_module(&mut collector);
+    tcx.hir_walk_toplevel_module(&mut collector);
 
     let ItemCollector {
         submodules,
@@ -1333,8 +1340,8 @@ impl<'tcx> ItemCollector<'tcx> {
 impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
     type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_item(&mut self, item: &'hir Item<'hir>) {
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 0d2acf96d08..2a201e23015 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -213,7 +213,7 @@ pub fn provide(providers: &mut Providers) {
     providers.fn_arg_names = |tcx, def_id| {
         let hir = tcx.hir();
         if let Some(body_id) = tcx.hir_node_by_def_id(def_id).body_id() {
-            tcx.arena.alloc_from_iter(hir.body_param_names(body_id))
+            tcx.arena.alloc_from_iter(tcx.hir_body_param_names(body_id))
         } else if let Node::TraitItem(&TraitItem {
             kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
             ..
diff --git a/compiler/rustc_middle/src/hir/nested_filter.rs b/compiler/rustc_middle/src/hir/nested_filter.rs
index adbe81bb22c..e18c28a8eac 100644
--- a/compiler/rustc_middle/src/hir/nested_filter.rs
+++ b/compiler/rustc_middle/src/hir/nested_filter.rs
@@ -1,5 +1,7 @@
 use rustc_hir::intravisit::nested_filter::NestedFilter;
 
+use crate::ty::TyCtxt;
+
 /// Do not visit nested item-like things, but visit nested things
 /// that are inside of an item-like.
 ///
@@ -12,8 +14,8 @@ use rustc_hir::intravisit::nested_filter::NestedFilter;
 /// and to have the visitor that visits the contents of each item
 /// using this setting.
 pub struct OnlyBodies(());
-impl<'hir> NestedFilter<'hir> for OnlyBodies {
-    type Map = crate::hir::map::Map<'hir>;
+impl<'tcx> NestedFilter<'tcx> for OnlyBodies {
+    type MaybeTyCtxt = TyCtxt<'tcx>;
     const INTER: bool = false;
     const INTRA: bool = true;
 }
@@ -24,8 +26,8 @@ impl<'hir> NestedFilter<'hir> for OnlyBodies {
 /// process everything within their lexical context. Typically you
 /// kick off the visit by doing `walk_krate()`.
 pub struct All(());
-impl<'hir> NestedFilter<'hir> for All {
-    type Map = crate::hir::map::Map<'hir>;
+impl<'tcx> NestedFilter<'tcx> for All {
+    type MaybeTyCtxt = TyCtxt<'tcx>;
     const INTER: bool = true;
     const INTRA: bool = true;
 }
diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs
index 692fe027c49..9f71971ea08 100644
--- a/compiler/rustc_middle/src/middle/mod.rs
+++ b/compiler/rustc_middle/src/middle/mod.rs
@@ -30,12 +30,7 @@ pub mod lib_features {
         }
     }
 }
-pub mod limits;
 pub mod privacy;
 pub mod region;
 pub mod resolve_bound_vars;
 pub mod stability;
-
-pub fn provide(providers: &mut crate::query::Providers) {
-    limits::provide(providers);
-}
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index c32cf5f8253..107c3198525 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -20,7 +20,22 @@ pub struct BasicBlocks<'tcx> {
 // Typically 95%+ of basic blocks have 4 or fewer predecessors.
 type Predecessors = IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>;
 
-type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u128>; 1]>>;
+/// Each `(target, switch)` entry in the map contains a list of switch values
+/// that lead to a `target` block from a `switch` block.
+///
+/// Note: this type is currently never instantiated, because it's only used for
+/// `BasicBlocks::switch_sources`, which is only called by backwards analyses
+/// that do `SwitchInt` handling, and we don't have any of those, not even in
+/// tests. See #95120 and #94576.
+type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[SwitchTargetValue; 1]>>;
+
+#[derive(Debug, Clone, Copy)]
+pub enum SwitchTargetValue {
+    // A normal switch value.
+    Normal(u128),
+    // The final "otherwise" fallback value.
+    Otherwise,
+}
 
 #[derive(Clone, Default, Debug)]
 struct Cache {
@@ -70,8 +85,8 @@ impl<'tcx> BasicBlocks<'tcx> {
         })
     }
 
-    /// `switch_sources()[&(target, switch)]` returns a list of switch
-    /// values that lead to a `target` block from a `switch` block.
+    /// Returns info about switch values that lead from one block to another
+    /// block. See `SwitchSources`.
     #[inline]
     pub fn switch_sources(&self) -> &SwitchSources {
         self.cache.switch_sources.get_or_init(|| {
@@ -82,9 +97,15 @@ impl<'tcx> BasicBlocks<'tcx> {
                 }) = &data.terminator
                 {
                     for (value, target) in targets.iter() {
-                        switch_sources.entry((target, bb)).or_default().push(Some(value));
+                        switch_sources
+                            .entry((target, bb))
+                            .or_default()
+                            .push(SwitchTargetValue::Normal(value));
                     }
-                    switch_sources.entry((targets.otherwise(), bb)).or_default().push(None);
+                    switch_sources
+                        .entry((targets.otherwise(), bb))
+                        .or_default()
+                        .push(SwitchTargetValue::Otherwise);
                 }
             }
             switch_sources
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 795cfcef2d3..528da4ca057 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -4,10 +4,10 @@
 
 use std::borrow::Cow;
 use std::fmt::{self, Debug, Formatter};
+use std::iter;
 use std::ops::{Index, IndexMut};
-use std::{iter, mem};
 
-pub use basic_blocks::BasicBlocks;
+pub use basic_blocks::{BasicBlocks, SwitchTargetValue};
 use either::Either;
 use polonius_engine::Atom;
 use rustc_abi::{FieldIdx, VariantIdx};
@@ -53,7 +53,6 @@ pub mod pretty;
 mod query;
 mod statement;
 mod syntax;
-pub mod tcx;
 mod terminator;
 
 pub mod traversal;
@@ -1365,66 +1364,6 @@ impl<'tcx> BasicBlockData<'tcx> {
         self.terminator.as_mut().expect("invalid terminator state")
     }
 
-    pub fn retain_statements<F>(&mut self, mut f: F)
-    where
-        F: FnMut(&mut Statement<'_>) -> bool,
-    {
-        for s in &mut self.statements {
-            if !f(s) {
-                s.make_nop();
-            }
-        }
-    }
-
-    pub fn expand_statements<F, I>(&mut self, mut f: F)
-    where
-        F: FnMut(&mut Statement<'tcx>) -> Option<I>,
-        I: iter::TrustedLen<Item = Statement<'tcx>>,
-    {
-        // Gather all the iterators we'll need to splice in, and their positions.
-        let mut splices: Vec<(usize, I)> = vec![];
-        let mut extra_stmts = 0;
-        for (i, s) in self.statements.iter_mut().enumerate() {
-            if let Some(mut new_stmts) = f(s) {
-                if let Some(first) = new_stmts.next() {
-                    // We can already store the first new statement.
-                    *s = first;
-
-                    // Save the other statements for optimized splicing.
-                    let remaining = new_stmts.size_hint().0;
-                    if remaining > 0 {
-                        splices.push((i + 1 + extra_stmts, new_stmts));
-                        extra_stmts += remaining;
-                    }
-                } else {
-                    s.make_nop();
-                }
-            }
-        }
-
-        // Splice in the new statements, from the end of the block.
-        // FIXME(eddyb) This could be more efficient with a "gap buffer"
-        // where a range of elements ("gap") is left uninitialized, with
-        // splicing adding new elements to the end of that gap and moving
-        // existing elements from before the gap to the end of the gap.
-        // For now, this is safe code, emulating a gap but initializing it.
-        let mut gap = self.statements.len()..self.statements.len() + extra_stmts;
-        self.statements.resize(
-            gap.end,
-            Statement { source_info: SourceInfo::outermost(DUMMY_SP), kind: StatementKind::Nop },
-        );
-        for (splice_start, new_stmts) in splices.into_iter().rev() {
-            let splice_end = splice_start + new_stmts.size_hint().0;
-            while gap.end > splice_end {
-                gap.start -= 1;
-                gap.end -= 1;
-                self.statements.swap(gap.start, gap.end);
-            }
-            self.statements.splice(splice_start..splice_end, new_stmts);
-            gap.end = splice_start;
-        }
-    }
-
     pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> {
         if index < self.statements.len() { &self.statements[index] } else { &self.terminator }
     }
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index d4a9aac3733..4a21b6ad237 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -6,8 +6,9 @@ use rustc_attr_parsing::InlineAttr;
 use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher, ToStableHashKey};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_data_structures::unord::UnordMap;
+use rustc_hashes::Hash128;
 use rustc_hir::ItemId;
 use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE};
 use rustc_index::Idx;
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index b0df6c71014..1e3b8d029e1 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1588,7 +1588,7 @@ pub fn write_allocations<'tcx>(
             Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
                 write!(w, " (static: {}", tcx.def_path_str(did))?;
                 if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup)
-                    && tcx.hir().body_const_context(body.source.def_id()).is_some()
+                    && tcx.hir_body_const_context(body.source.def_id()).is_some()
                 {
                     // Statics may be cyclic and evaluating them too early
                     // in the MIR pipeline may cause cycle errors even though
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index d345c99f902..595a5e548b0 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -1,7 +1,10 @@
 //! Functionality for statements, operands, places, and things that appear in them.
 
+use tracing::{debug, instrument};
+
 use super::interpret::GlobalAlloc;
 use super::*;
+use crate::ty::CoroutineArgsExt;
 
 ///////////////////////////////////////////////////////////////////////////
 // Statements
@@ -19,15 +22,6 @@ impl Statement<'_> {
     pub fn make_nop(&mut self) {
         self.kind = StatementKind::Nop
     }
-
-    /// Changes a statement to a nop and returns the original statement.
-    #[must_use = "If you don't need the statement, use `make_nop` instead"]
-    pub fn replace_nop(&mut self) -> Self {
-        Statement {
-            source_info: self.source_info,
-            kind: mem::replace(&mut self.kind, StatementKind::Nop),
-        }
-    }
 }
 
 impl<'tcx> StatementKind<'tcx> {
@@ -49,6 +43,162 @@ impl<'tcx> StatementKind<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Places
 
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
+pub struct PlaceTy<'tcx> {
+    pub ty: Ty<'tcx>,
+    /// Downcast to a particular variant of an enum or a coroutine, if included.
+    pub variant_index: Option<VariantIdx>,
+}
+
+// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
+#[cfg(target_pointer_width = "64")]
+rustc_data_structures::static_assert_size!(PlaceTy<'_>, 16);
+
+impl<'tcx> PlaceTy<'tcx> {
+    #[inline]
+    pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
+        PlaceTy { ty, variant_index: None }
+    }
+
+    /// `place_ty.field_ty(tcx, f)` computes the type of a given field.
+    ///
+    /// Most clients of `PlaceTy` can instead just extract the relevant type
+    /// directly from their `PlaceElem`, but some instances of `ProjectionElem<V, T>`
+    /// do not carry a `Ty` for `T`.
+    ///
+    /// Note that the resulting type has not been normalized.
+    #[instrument(level = "debug", skip(tcx), ret)]
+    pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> {
+        if let Some(variant_index) = self.variant_index {
+            match *self.ty.kind() {
+                ty::Adt(adt_def, args) if adt_def.is_enum() => {
+                    adt_def.variant(variant_index).fields[f].ty(tcx, args)
+                }
+                ty::Coroutine(def_id, args) => {
+                    let mut variants = args.as_coroutine().state_tys(def_id, tcx);
+                    let Some(mut variant) = variants.nth(variant_index.into()) else {
+                        bug!("variant {variant_index:?} of coroutine out of range: {self:?}");
+                    };
+
+                    variant
+                        .nth(f.index())
+                        .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}"))
+                }
+                _ => bug!("can't downcast non-adt non-coroutine type: {self:?}"),
+            }
+        } else {
+            match self.ty.kind() {
+                ty::Adt(adt_def, args) if !adt_def.is_enum() => {
+                    adt_def.non_enum_variant().fields[f].ty(tcx, args)
+                }
+                ty::Closure(_, args) => args
+                    .as_closure()
+                    .upvar_tys()
+                    .get(f.index())
+                    .copied()
+                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
+                ty::CoroutineClosure(_, args) => args
+                    .as_coroutine_closure()
+                    .upvar_tys()
+                    .get(f.index())
+                    .copied()
+                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
+                // Only prefix fields (upvars and current state) are
+                // accessible without a variant index.
+                ty::Coroutine(_, args) => args
+                    .as_coroutine()
+                    .prefix_tys()
+                    .get(f.index())
+                    .copied()
+                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
+                ty::Tuple(tys) => tys
+                    .get(f.index())
+                    .copied()
+                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
+                _ => bug!("can't project out of {self:?}"),
+            }
+        }
+    }
+
+    pub fn multi_projection_ty(
+        self,
+        tcx: TyCtxt<'tcx>,
+        elems: &[PlaceElem<'tcx>],
+    ) -> PlaceTy<'tcx> {
+        elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem))
+    }
+
+    /// Convenience wrapper around `projection_ty_core` for
+    /// `PlaceElem`, where we can just use the `Ty` that is already
+    /// stored inline on field projection elems.
+    pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
+        self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty)
+    }
+
+    /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
+    /// projects `place_ty` onto `elem`, returning the appropriate
+    /// `Ty` or downcast variant corresponding to that projection.
+    /// The `handle_field` callback must map a `FieldIdx` to its `Ty`,
+    /// (which should be trivial when `T` = `Ty`).
+    pub fn projection_ty_core<V, T>(
+        self,
+        tcx: TyCtxt<'tcx>,
+        elem: &ProjectionElem<V, T>,
+        mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>,
+        mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>,
+    ) -> PlaceTy<'tcx>
+    where
+        V: ::std::fmt::Debug,
+        T: ::std::fmt::Debug + Copy,
+    {
+        if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) {
+            bug!("cannot use non field projection on downcasted place")
+        }
+        let answer = match *elem {
+            ProjectionElem::Deref => {
+                let ty = self.ty.builtin_deref(true).unwrap_or_else(|| {
+                    bug!("deref projection of non-dereferenceable ty {:?}", self)
+                });
+                PlaceTy::from_ty(ty)
+            }
+            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
+                PlaceTy::from_ty(self.ty.builtin_index().unwrap())
+            }
+            ProjectionElem::Subslice { from, to, from_end } => {
+                PlaceTy::from_ty(match self.ty.kind() {
+                    ty::Slice(..) => self.ty,
+                    ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from),
+                    ty::Array(inner, size) if from_end => {
+                        let size = size
+                            .try_to_target_usize(tcx)
+                            .expect("expected subslice projection on fixed-size array");
+                        let len = size - from - to;
+                        Ty::new_array(tcx, *inner, len)
+                    }
+                    _ => bug!("cannot subslice non-array type: `{:?}`", self),
+                })
+            }
+            ProjectionElem::Downcast(_name, index) => {
+                PlaceTy { ty: self.ty, variant_index: Some(index) }
+            }
+            ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
+            ProjectionElem::OpaqueCast(ty) => {
+                PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
+            }
+            ProjectionElem::Subtype(ty) => {
+                PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
+            }
+
+            // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
+            ProjectionElem::UnwrapUnsafeBinder(ty) => {
+                PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
+            }
+        };
+        debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
+        answer
+    }
+}
+
 impl<V, T> ProjectionElem<V, T> {
     /// Returns `true` if the target of this projection may refer to a different region of memory
     /// than the base.
@@ -192,6 +342,25 @@ impl<'tcx> Place<'tcx> {
 
         self.as_ref().project_deeper(more_projections, tcx)
     }
+
+    pub fn ty_from<D: ?Sized>(
+        local: Local,
+        projection: &[PlaceElem<'tcx>],
+        local_decls: &D,
+        tcx: TyCtxt<'tcx>,
+    ) -> PlaceTy<'tcx>
+    where
+        D: HasLocalDecls<'tcx>,
+    {
+        PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection)
+    }
+
+    pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
+    where
+        D: HasLocalDecls<'tcx>,
+    {
+        Place::ty_from(self.local, self.projection, local_decls, tcx)
+    }
 }
 
 impl From<Local> for Place<'_> {
@@ -294,6 +463,13 @@ impl<'tcx> PlaceRef<'tcx> {
 
         Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
     }
+
+    pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
+    where
+        D: HasLocalDecls<'tcx>,
+    {
+        Place::ty_from(self.local, self.projection, local_decls, tcx)
+    }
 }
 
 impl From<Local> for PlaceRef<'_> {
@@ -388,6 +564,28 @@ impl<'tcx> Operand<'tcx> {
         let const_ty = self.constant()?.const_.ty();
         if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
     }
+
+    pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
+    where
+        D: HasLocalDecls<'tcx>,
+    {
+        match self {
+            &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
+            Operand::Constant(c) => c.const_.ty(),
+        }
+    }
+
+    pub fn span<D: ?Sized>(&self, local_decls: &D) -> Span
+    where
+        D: HasLocalDecls<'tcx>,
+    {
+        match self {
+            &Operand::Copy(ref l) | &Operand::Move(ref l) => {
+                local_decls.local_decls()[l.local].source_info.span
+            }
+            Operand::Constant(c) => c.span,
+        }
+    }
 }
 
 impl<'tcx> ConstOperand<'tcx> {
@@ -413,6 +611,11 @@ impl<'tcx> ConstOperand<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 /// Rvalues
 
+pub enum RvalueInitializationState {
+    Shallow,
+    Deep,
+}
+
 impl<'tcx> Rvalue<'tcx> {
     /// Returns true if rvalue can be safely removed when the result is unused.
     #[inline]
@@ -452,6 +655,70 @@ impl<'tcx> Rvalue<'tcx> {
             | Rvalue::WrapUnsafeBinder(_, _) => true,
         }
     }
+
+    pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
+    where
+        D: HasLocalDecls<'tcx>,
+    {
+        match *self {
+            Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
+            Rvalue::Repeat(ref operand, count) => {
+                Ty::new_array_with_const_len(tcx, operand.ty(local_decls, tcx), count)
+            }
+            Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did),
+            Rvalue::Ref(reg, bk, ref place) => {
+                let place_ty = place.ty(local_decls, tcx).ty;
+                Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy())
+            }
+            Rvalue::RawPtr(kind, ref place) => {
+                let place_ty = place.ty(local_decls, tcx).ty;
+                Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy())
+            }
+            Rvalue::Len(..) => tcx.types.usize,
+            Rvalue::Cast(.., ty) => ty,
+            Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
+                let lhs_ty = lhs.ty(local_decls, tcx);
+                let rhs_ty = rhs.ty(local_decls, tcx);
+                op.ty(tcx, lhs_ty, rhs_ty)
+            }
+            Rvalue::UnaryOp(op, ref operand) => {
+                let arg_ty = operand.ty(local_decls, tcx);
+                op.ty(tcx, arg_ty)
+            }
+            Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
+            Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
+                tcx.types.usize
+            }
+            Rvalue::NullaryOp(NullOp::ContractChecks, _)
+            | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool,
+            Rvalue::Aggregate(ref ak, ref ops) => match **ak {
+                AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
+                AggregateKind::Tuple => {
+                    Ty::new_tup_from_iter(tcx, ops.iter().map(|op| op.ty(local_decls, tcx)))
+                }
+                AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args),
+                AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args),
+                AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args),
+                AggregateKind::CoroutineClosure(did, args) => {
+                    Ty::new_coroutine_closure(tcx, did, args)
+                }
+                AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability),
+            },
+            Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
+            Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
+            Rvalue::WrapUnsafeBinder(_, ty) => ty,
+        }
+    }
+
+    #[inline]
+    /// Returns `true` if this rvalue is deeply initialized (most rvalues) or
+    /// whether its only shallowly initialized (`Rvalue::Box`).
+    pub fn initialization_state(&self) -> RvalueInitializationState {
+        match *self {
+            Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow,
+            _ => RvalueInitializationState::Deep,
+        }
+    }
 }
 
 impl BorrowKind {
@@ -474,4 +741,124 @@ impl BorrowKind {
             BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true,
         }
     }
+
+    pub fn to_mutbl_lossy(self) -> hir::Mutability {
+        match self {
+            BorrowKind::Mut { .. } => hir::Mutability::Mut,
+            BorrowKind::Shared => hir::Mutability::Not,
+
+            // We have no type corresponding to a shallow borrow, so use
+            // `&` as an approximation.
+            BorrowKind::Fake(_) => hir::Mutability::Not,
+        }
+    }
+}
+
+impl<'tcx> UnOp {
+    pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> {
+        match self {
+            UnOp::Not | UnOp::Neg => arg_ty,
+            UnOp::PtrMetadata => arg_ty.pointee_metadata_ty_or_projection(tcx),
+        }
+    }
+}
+
+impl<'tcx> BinOp {
+    pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> {
+        // FIXME: handle SIMD correctly
+        match self {
+            &BinOp::Add
+            | &BinOp::AddUnchecked
+            | &BinOp::Sub
+            | &BinOp::SubUnchecked
+            | &BinOp::Mul
+            | &BinOp::MulUnchecked
+            | &BinOp::Div
+            | &BinOp::Rem
+            | &BinOp::BitXor
+            | &BinOp::BitAnd
+            | &BinOp::BitOr => {
+                // these should be integers or floats of the same size.
+                assert_eq!(lhs_ty, rhs_ty);
+                lhs_ty
+            }
+            &BinOp::AddWithOverflow | &BinOp::SubWithOverflow | &BinOp::MulWithOverflow => {
+                // these should be integers of the same size.
+                assert_eq!(lhs_ty, rhs_ty);
+                Ty::new_tup(tcx, &[lhs_ty, tcx.types.bool])
+            }
+            &BinOp::Shl
+            | &BinOp::ShlUnchecked
+            | &BinOp::Shr
+            | &BinOp::ShrUnchecked
+            | &BinOp::Offset => {
+                lhs_ty // lhs_ty can be != rhs_ty
+            }
+            &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
+                tcx.types.bool
+            }
+            &BinOp::Cmp => {
+                // these should be integer-like types of the same size.
+                assert_eq!(lhs_ty, rhs_ty);
+                tcx.ty_ordering_enum(None)
+            }
+        }
+    }
+    pub(crate) fn to_hir_binop(self) -> hir::BinOpKind {
+        match self {
+            // HIR `+`/`-`/`*` can map to either of these MIR BinOp, depending
+            // on whether overflow checks are enabled or not.
+            BinOp::Add | BinOp::AddWithOverflow => hir::BinOpKind::Add,
+            BinOp::Sub | BinOp::SubWithOverflow => hir::BinOpKind::Sub,
+            BinOp::Mul | BinOp::MulWithOverflow => hir::BinOpKind::Mul,
+            BinOp::Div => hir::BinOpKind::Div,
+            BinOp::Rem => hir::BinOpKind::Rem,
+            BinOp::BitXor => hir::BinOpKind::BitXor,
+            BinOp::BitAnd => hir::BinOpKind::BitAnd,
+            BinOp::BitOr => hir::BinOpKind::BitOr,
+            BinOp::Shl => hir::BinOpKind::Shl,
+            BinOp::Shr => hir::BinOpKind::Shr,
+            BinOp::Eq => hir::BinOpKind::Eq,
+            BinOp::Ne => hir::BinOpKind::Ne,
+            BinOp::Lt => hir::BinOpKind::Lt,
+            BinOp::Gt => hir::BinOpKind::Gt,
+            BinOp::Le => hir::BinOpKind::Le,
+            BinOp::Ge => hir::BinOpKind::Ge,
+            // We don't have HIR syntax for these.
+            BinOp::Cmp
+            | BinOp::AddUnchecked
+            | BinOp::SubUnchecked
+            | BinOp::MulUnchecked
+            | BinOp::ShlUnchecked
+            | BinOp::ShrUnchecked
+            | BinOp::Offset => {
+                unreachable!()
+            }
+        }
+    }
+
+    /// If this is a `FooWithOverflow`, return `Some(Foo)`.
+    pub fn overflowing_to_wrapping(self) -> Option<BinOp> {
+        Some(match self {
+            BinOp::AddWithOverflow => BinOp::Add,
+            BinOp::SubWithOverflow => BinOp::Sub,
+            BinOp::MulWithOverflow => BinOp::Mul,
+            _ => return None,
+        })
+    }
+
+    /// Returns whether this is a `FooWithOverflow`
+    pub fn is_overflowing(self) -> bool {
+        self.overflowing_to_wrapping().is_some()
+    }
+
+    /// If this is a `Foo`, return `Some(FooWithOverflow)`.
+    pub fn wrapping_to_overflowing(self) -> Option<BinOp> {
+        Some(match self {
+            BinOp::Add => BinOp::AddWithOverflow,
+            BinOp::Sub => BinOp::SubWithOverflow,
+            BinOp::Mul => BinOp::MulWithOverflow,
+            _ => return None,
+        })
+    }
 }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 9cec8d832dd..389792a04f8 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1015,22 +1015,30 @@ impl TerminatorKind<'_> {
 
 #[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub struct SwitchTargets {
-    /// Possible values. The locations to branch to in each case
-    /// are found in the corresponding indices from the `targets` vector.
+    /// Possible values. For each value, the location to branch to is found in
+    /// the corresponding element in the `targets` vector.
     pub(super) values: SmallVec<[Pu128; 1]>,
 
-    /// Possible branch sites. The last element of this vector is used
-    /// for the otherwise branch, so targets.len() == values.len() + 1
-    /// should hold.
+    /// Possible branch targets. The last element of this vector is used for
+    /// the "otherwise" branch, so `targets.len() == values.len() + 1` always
+    /// holds.
     //
-    // This invariant is quite non-obvious and also could be improved.
-    // One way to make this invariant is to have something like this instead:
+    // Note: This invariant is non-obvious and easy to violate. This would be a
+    // more rigorous representation:
     //
-    // branches: Vec<(ConstInt, BasicBlock)>,
-    // otherwise: Option<BasicBlock> // exhaustive if None
+    //   normal: SmallVec<[(Pu128, BasicBlock); 1]>,
+    //   otherwise: BasicBlock,
     //
-    // However we’ve decided to keep this as-is until we figure a case
-    // where some other approach seems to be strictly better than other.
+    // But it's important to have the targets in a sliceable type, because
+    // target slices show up elsewhere. E.g. `TerminatorKind::InlineAsm` has a
+    // boxed slice, and `TerminatorKind::FalseEdge` has a single target that
+    // can be converted to a slice with `slice::from_ref`.
+    //
+    // Why does this matter? In functions like `TerminatorKind::successors` we
+    // return `impl Iterator` and a non-slice-of-targets representation here
+    // causes problems because multiple different concrete iterator types would
+    // be involved and we would need a boxed trait object, which requires an
+    // allocation, which is expensive if done frequently.
     pub(super) targets: SmallVec<[BasicBlock; 2]>,
 }
 
@@ -1125,7 +1133,7 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
 ///
 ///  1. The address in memory that the place refers to.
 ///  2. The provenance with which the place is being accessed.
-///  3. The type of the place and an optional variant index. See [`PlaceTy`][super::tcx::PlaceTy].
+///  3. The type of the place and an optional variant index. See [`PlaceTy`][super::PlaceTy].
 ///  4. Optionally, some metadata. This exists if and only if the type of the place is not `Sized`.
 ///
 /// We'll give a description below of how all pieces of the place except for the provenance are
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
deleted file mode 100644
index 862f78d7259..00000000000
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ /dev/null
@@ -1,416 +0,0 @@
-/*!
- * Methods for the various MIR types. These are intended for use after
- * building is complete.
- */
-
-use rustc_hir as hir;
-use tracing::{debug, instrument};
-use ty::CoroutineArgsExt;
-
-use crate::mir::*;
-
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
-pub struct PlaceTy<'tcx> {
-    pub ty: Ty<'tcx>,
-    /// Downcast to a particular variant of an enum or a coroutine, if included.
-    pub variant_index: Option<VariantIdx>,
-}
-
-// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
-#[cfg(target_pointer_width = "64")]
-rustc_data_structures::static_assert_size!(PlaceTy<'_>, 16);
-
-impl<'tcx> PlaceTy<'tcx> {
-    #[inline]
-    pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
-        PlaceTy { ty, variant_index: None }
-    }
-
-    /// `place_ty.field_ty(tcx, f)` computes the type of a given field.
-    ///
-    /// Most clients of `PlaceTy` can instead just extract the relevant type
-    /// directly from their `PlaceElem`, but some instances of `ProjectionElem<V, T>`
-    /// do not carry a `Ty` for `T`.
-    ///
-    /// Note that the resulting type has not been normalized.
-    #[instrument(level = "debug", skip(tcx), ret)]
-    pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> {
-        if let Some(variant_index) = self.variant_index {
-            match *self.ty.kind() {
-                ty::Adt(adt_def, args) if adt_def.is_enum() => {
-                    adt_def.variant(variant_index).fields[f].ty(tcx, args)
-                }
-                ty::Coroutine(def_id, args) => {
-                    let mut variants = args.as_coroutine().state_tys(def_id, tcx);
-                    let Some(mut variant) = variants.nth(variant_index.into()) else {
-                        bug!("variant {variant_index:?} of coroutine out of range: {self:?}");
-                    };
-
-                    variant
-                        .nth(f.index())
-                        .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}"))
-                }
-                _ => bug!("can't downcast non-adt non-coroutine type: {self:?}"),
-            }
-        } else {
-            match self.ty.kind() {
-                ty::Adt(adt_def, args) if !adt_def.is_enum() => {
-                    adt_def.non_enum_variant().fields[f].ty(tcx, args)
-                }
-                ty::Closure(_, args) => args
-                    .as_closure()
-                    .upvar_tys()
-                    .get(f.index())
-                    .copied()
-                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
-                ty::CoroutineClosure(_, args) => args
-                    .as_coroutine_closure()
-                    .upvar_tys()
-                    .get(f.index())
-                    .copied()
-                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
-                // Only prefix fields (upvars and current state) are
-                // accessible without a variant index.
-                ty::Coroutine(_, args) => args
-                    .as_coroutine()
-                    .prefix_tys()
-                    .get(f.index())
-                    .copied()
-                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
-                ty::Tuple(tys) => tys
-                    .get(f.index())
-                    .copied()
-                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
-                _ => bug!("can't project out of {self:?}"),
-            }
-        }
-    }
-
-    pub fn multi_projection_ty(
-        self,
-        tcx: TyCtxt<'tcx>,
-        elems: &[PlaceElem<'tcx>],
-    ) -> PlaceTy<'tcx> {
-        elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem))
-    }
-
-    /// Convenience wrapper around `projection_ty_core` for
-    /// `PlaceElem`, where we can just use the `Ty` that is already
-    /// stored inline on field projection elems.
-    pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
-        self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty)
-    }
-
-    /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
-    /// projects `place_ty` onto `elem`, returning the appropriate
-    /// `Ty` or downcast variant corresponding to that projection.
-    /// The `handle_field` callback must map a `FieldIdx` to its `Ty`,
-    /// (which should be trivial when `T` = `Ty`).
-    pub fn projection_ty_core<V, T>(
-        self,
-        tcx: TyCtxt<'tcx>,
-        elem: &ProjectionElem<V, T>,
-        mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>,
-        mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>,
-    ) -> PlaceTy<'tcx>
-    where
-        V: ::std::fmt::Debug,
-        T: ::std::fmt::Debug + Copy,
-    {
-        if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) {
-            bug!("cannot use non field projection on downcasted place")
-        }
-        let answer = match *elem {
-            ProjectionElem::Deref => {
-                let ty = self.ty.builtin_deref(true).unwrap_or_else(|| {
-                    bug!("deref projection of non-dereferenceable ty {:?}", self)
-                });
-                PlaceTy::from_ty(ty)
-            }
-            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
-                PlaceTy::from_ty(self.ty.builtin_index().unwrap())
-            }
-            ProjectionElem::Subslice { from, to, from_end } => {
-                PlaceTy::from_ty(match self.ty.kind() {
-                    ty::Slice(..) => self.ty,
-                    ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from),
-                    ty::Array(inner, size) if from_end => {
-                        let size = size
-                            .try_to_target_usize(tcx)
-                            .expect("expected subslice projection on fixed-size array");
-                        let len = size - from - to;
-                        Ty::new_array(tcx, *inner, len)
-                    }
-                    _ => bug!("cannot subslice non-array type: `{:?}`", self),
-                })
-            }
-            ProjectionElem::Downcast(_name, index) => {
-                PlaceTy { ty: self.ty, variant_index: Some(index) }
-            }
-            ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
-            ProjectionElem::OpaqueCast(ty) => {
-                PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
-            }
-            ProjectionElem::Subtype(ty) => {
-                PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
-            }
-
-            // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
-            ProjectionElem::UnwrapUnsafeBinder(ty) => {
-                PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
-            }
-        };
-        debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
-        answer
-    }
-}
-
-impl<'tcx> Place<'tcx> {
-    pub fn ty_from<D: ?Sized>(
-        local: Local,
-        projection: &[PlaceElem<'tcx>],
-        local_decls: &D,
-        tcx: TyCtxt<'tcx>,
-    ) -> PlaceTy<'tcx>
-    where
-        D: HasLocalDecls<'tcx>,
-    {
-        PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection)
-    }
-
-    pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
-    where
-        D: HasLocalDecls<'tcx>,
-    {
-        Place::ty_from(self.local, self.projection, local_decls, tcx)
-    }
-}
-
-impl<'tcx> PlaceRef<'tcx> {
-    pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
-    where
-        D: HasLocalDecls<'tcx>,
-    {
-        Place::ty_from(self.local, self.projection, local_decls, tcx)
-    }
-}
-
-pub enum RvalueInitializationState {
-    Shallow,
-    Deep,
-}
-
-impl<'tcx> Rvalue<'tcx> {
-    pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
-    where
-        D: HasLocalDecls<'tcx>,
-    {
-        match *self {
-            Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
-            Rvalue::Repeat(ref operand, count) => {
-                Ty::new_array_with_const_len(tcx, operand.ty(local_decls, tcx), count)
-            }
-            Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did),
-            Rvalue::Ref(reg, bk, ref place) => {
-                let place_ty = place.ty(local_decls, tcx).ty;
-                Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy())
-            }
-            Rvalue::RawPtr(kind, ref place) => {
-                let place_ty = place.ty(local_decls, tcx).ty;
-                Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy())
-            }
-            Rvalue::Len(..) => tcx.types.usize,
-            Rvalue::Cast(.., ty) => ty,
-            Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
-                let lhs_ty = lhs.ty(local_decls, tcx);
-                let rhs_ty = rhs.ty(local_decls, tcx);
-                op.ty(tcx, lhs_ty, rhs_ty)
-            }
-            Rvalue::UnaryOp(op, ref operand) => {
-                let arg_ty = operand.ty(local_decls, tcx);
-                op.ty(tcx, arg_ty)
-            }
-            Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
-            Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
-                tcx.types.usize
-            }
-            Rvalue::NullaryOp(NullOp::ContractChecks, _)
-            | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool,
-            Rvalue::Aggregate(ref ak, ref ops) => match **ak {
-                AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
-                AggregateKind::Tuple => {
-                    Ty::new_tup_from_iter(tcx, ops.iter().map(|op| op.ty(local_decls, tcx)))
-                }
-                AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args),
-                AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args),
-                AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args),
-                AggregateKind::CoroutineClosure(did, args) => {
-                    Ty::new_coroutine_closure(tcx, did, args)
-                }
-                AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability),
-            },
-            Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
-            Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
-            Rvalue::WrapUnsafeBinder(_, ty) => ty,
-        }
-    }
-
-    #[inline]
-    /// Returns `true` if this rvalue is deeply initialized (most rvalues) or
-    /// whether its only shallowly initialized (`Rvalue::Box`).
-    pub fn initialization_state(&self) -> RvalueInitializationState {
-        match *self {
-            Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow,
-            _ => RvalueInitializationState::Deep,
-        }
-    }
-}
-
-impl<'tcx> Operand<'tcx> {
-    pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
-    where
-        D: HasLocalDecls<'tcx>,
-    {
-        match self {
-            &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
-            Operand::Constant(c) => c.const_.ty(),
-        }
-    }
-
-    pub fn span<D: ?Sized>(&self, local_decls: &D) -> Span
-    where
-        D: HasLocalDecls<'tcx>,
-    {
-        match self {
-            &Operand::Copy(ref l) | &Operand::Move(ref l) => {
-                local_decls.local_decls()[l.local].source_info.span
-            }
-            Operand::Constant(c) => c.span,
-        }
-    }
-}
-
-impl<'tcx> BinOp {
-    pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> {
-        // FIXME: handle SIMD correctly
-        match self {
-            &BinOp::Add
-            | &BinOp::AddUnchecked
-            | &BinOp::Sub
-            | &BinOp::SubUnchecked
-            | &BinOp::Mul
-            | &BinOp::MulUnchecked
-            | &BinOp::Div
-            | &BinOp::Rem
-            | &BinOp::BitXor
-            | &BinOp::BitAnd
-            | &BinOp::BitOr => {
-                // these should be integers or floats of the same size.
-                assert_eq!(lhs_ty, rhs_ty);
-                lhs_ty
-            }
-            &BinOp::AddWithOverflow | &BinOp::SubWithOverflow | &BinOp::MulWithOverflow => {
-                // these should be integers of the same size.
-                assert_eq!(lhs_ty, rhs_ty);
-                Ty::new_tup(tcx, &[lhs_ty, tcx.types.bool])
-            }
-            &BinOp::Shl
-            | &BinOp::ShlUnchecked
-            | &BinOp::Shr
-            | &BinOp::ShrUnchecked
-            | &BinOp::Offset => {
-                lhs_ty // lhs_ty can be != rhs_ty
-            }
-            &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
-                tcx.types.bool
-            }
-            &BinOp::Cmp => {
-                // these should be integer-like types of the same size.
-                assert_eq!(lhs_ty, rhs_ty);
-                tcx.ty_ordering_enum(None)
-            }
-        }
-    }
-}
-
-impl<'tcx> UnOp {
-    pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> {
-        match self {
-            UnOp::Not | UnOp::Neg => arg_ty,
-            UnOp::PtrMetadata => arg_ty.pointee_metadata_ty_or_projection(tcx),
-        }
-    }
-}
-
-impl BorrowKind {
-    pub fn to_mutbl_lossy(self) -> hir::Mutability {
-        match self {
-            BorrowKind::Mut { .. } => hir::Mutability::Mut,
-            BorrowKind::Shared => hir::Mutability::Not,
-
-            // We have no type corresponding to a shallow borrow, so use
-            // `&` as an approximation.
-            BorrowKind::Fake(_) => hir::Mutability::Not,
-        }
-    }
-}
-
-impl BinOp {
-    pub(crate) fn to_hir_binop(self) -> hir::BinOpKind {
-        match self {
-            // HIR `+`/`-`/`*` can map to either of these MIR BinOp, depending
-            // on whether overflow checks are enabled or not.
-            BinOp::Add | BinOp::AddWithOverflow => hir::BinOpKind::Add,
-            BinOp::Sub | BinOp::SubWithOverflow => hir::BinOpKind::Sub,
-            BinOp::Mul | BinOp::MulWithOverflow => hir::BinOpKind::Mul,
-            BinOp::Div => hir::BinOpKind::Div,
-            BinOp::Rem => hir::BinOpKind::Rem,
-            BinOp::BitXor => hir::BinOpKind::BitXor,
-            BinOp::BitAnd => hir::BinOpKind::BitAnd,
-            BinOp::BitOr => hir::BinOpKind::BitOr,
-            BinOp::Shl => hir::BinOpKind::Shl,
-            BinOp::Shr => hir::BinOpKind::Shr,
-            BinOp::Eq => hir::BinOpKind::Eq,
-            BinOp::Ne => hir::BinOpKind::Ne,
-            BinOp::Lt => hir::BinOpKind::Lt,
-            BinOp::Gt => hir::BinOpKind::Gt,
-            BinOp::Le => hir::BinOpKind::Le,
-            BinOp::Ge => hir::BinOpKind::Ge,
-            // We don't have HIR syntax for these.
-            BinOp::Cmp
-            | BinOp::AddUnchecked
-            | BinOp::SubUnchecked
-            | BinOp::MulUnchecked
-            | BinOp::ShlUnchecked
-            | BinOp::ShrUnchecked
-            | BinOp::Offset => {
-                unreachable!()
-            }
-        }
-    }
-
-    /// If this is a `FooWithOverflow`, return `Some(Foo)`.
-    pub fn overflowing_to_wrapping(self) -> Option<BinOp> {
-        Some(match self {
-            BinOp::AddWithOverflow => BinOp::Add,
-            BinOp::SubWithOverflow => BinOp::Sub,
-            BinOp::MulWithOverflow => BinOp::Mul,
-            _ => return None,
-        })
-    }
-
-    /// Returns whether this is a `FooWithOverflow`
-    pub fn is_overflowing(self) -> bool {
-        self.overflowing_to_wrapping().is_some()
-    }
-
-    /// If this is a `Foo`, return `Some(FooWithOverflow)`.
-    pub fn wrapping_to_overflowing(self) -> Option<BinOp> {
-        Some(match self {
-            BinOp::Add => BinOp::AddWithOverflow,
-            BinOp::Sub => BinOp::SubWithOverflow,
-            BinOp::Mul => BinOp::MulWithOverflow,
-            _ => return None,
-        })
-    }
-}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index cd81890598e..693823b4af4 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -163,7 +163,7 @@ rustc_queries! {
 
     /// The items in a module.
     ///
-    /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
+    /// This can be conveniently accessed by `tcx.hir_visit_item_likes_in_module`.
     /// Avoid calling this query directly.
     query hir_module_items(key: LocalModDefId) -> &'tcx rustc_middle::hir::ModuleItems {
         arena_cache
@@ -771,7 +771,7 @@ rustc_queries! {
     query type_param_predicates(
         key: (LocalDefId, LocalDefId, rustc_span::Ident)
     ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
-        desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) }
+        desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir_ty_param_name(key.1) }
     }
 
     query trait_def(key: DefId) -> &'tcx ty::TraitDef {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 2ab8750f727..98cc00c367c 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -376,7 +376,6 @@ pub enum ExprKind<'tcx> {
     /// A `match` expression.
     Match {
         scrutinee: ExprId,
-        scrutinee_hir_id: HirId,
         arms: Box<[ArmId]>,
         match_source: MatchSource,
     },
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index cb8dc692148..35893ad953d 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -2079,7 +2079,7 @@ impl<'tcx> TyCtxt<'tcx> {
     ) -> Vec<&'tcx hir::Ty<'tcx>> {
         let hir_id = self.local_def_id_to_hir_id(scope_def_id);
         let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) =
-            self.hir().fn_decl_by_hir_id(hir_id)
+            self.hir_fn_decl_by_hir_id(hir_id)
         else {
             return vec![];
         };
@@ -2099,7 +2099,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let hir_id = self.local_def_id_to_hir_id(scope_def_id);
         let mut v = TraitObjectVisitor(vec![], self.hir());
         // when the return type is a type alias
-        if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id)
+        if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir_fn_decl_by_hir_id(hir_id)
             && let hir::TyKind::Path(hir::QPath::Resolved(
                 None,
                 hir::Path { res: hir::def::Res::Def(DefKind::TyAlias, def_id), .. }, )) = hir_output.kind
@@ -2168,6 +2168,10 @@ impl<'tcx> TyCtxt<'tcx> {
         self.limits(()).move_size_limit
     }
 
+    pub fn pattern_complexity_limit(self) -> Limit {
+        self.limits(()).pattern_complexity_limit
+    }
+
     /// All traits in the crate graph, including those not visible to the user.
     pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
         iter::once(LOCAL_CRATE)
@@ -3293,9 +3297,9 @@ pub fn provide(providers: &mut Providers) {
     providers.extern_mod_stmt_cnum =
         |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
     providers.is_panic_runtime =
-        |tcx, LocalCrate| contains_name(tcx.hir().krate_attrs(), sym::panic_runtime);
+        |tcx, LocalCrate| contains_name(tcx.hir_krate_attrs(), sym::panic_runtime);
     providers.is_compiler_builtins =
-        |tcx, LocalCrate| contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins);
+        |tcx, LocalCrate| contains_name(tcx.hir_krate_attrs(), sym::compiler_builtins);
     providers.has_panic_handler = |tcx, LocalCrate| {
         // We want to check if the panic handler was defined in this crate
         tcx.lang_items().panic_impl().is_some_and(|did| did.is_local())
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index fd84d75b53f..56a38a84c9f 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -495,7 +495,7 @@ impl<'tcx> GenericArgs<'tcx> {
         self.iter().filter_map(|k| k.as_const())
     }
 
-    /// Returns generic arguments that are not lifetimes or host effect params.
+    /// Returns generic arguments that are not lifetimes.
     #[inline]
     pub fn non_erasable_generics(
         &'tcx self,
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index e5a4e38c875..19fa8323574 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -11,6 +11,7 @@ use rustc_error_messages::DiagMessage;
 use rustc_errors::{
     Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
 };
+use rustc_hashes::Hash64;
 use rustc_hir::LangItem;
 use rustc_hir::def_id::DefId;
 use rustc_index::IndexVec;
@@ -228,11 +229,32 @@ impl fmt::Display for ValidityRequirement {
 
 #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
 pub enum LayoutError<'tcx> {
+    /// A type doesn't have a sensible layout.
+    ///
+    /// This variant is used for layout errors that don't necessarily cause
+    /// compile errors.
+    ///
+    /// For example, this can happen if a struct contains an unsized type in a
+    /// non-tail field, but has an unsatisfiable bound like `str: Sized`.
     Unknown(Ty<'tcx>),
+    /// The size of a type exceeds [`TargetDataLayout::obj_size_bound`].
     SizeOverflow(Ty<'tcx>),
+    /// The layout can vary due to a generic parameter.
+    ///
+    /// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout
+    /// may become computable after further instantiating the generic parameter(s).
     TooGeneric(Ty<'tcx>),
+    /// An alias failed to normalize.
+    ///
+    /// This variant is necessary, because, due to trait solver incompleteness, it is
+    /// possible than an alias that was rigid during analysis fails to normalize after
+    /// revealing opaque types.
+    ///
+    /// See `tests/ui/layout/normalization-failure.rs` for an example.
     NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
+    /// A non-layout error is reported elsewhere.
     ReferencesError(ErrorGuaranteed),
+    /// A type has cyclic layout, i.e. the type contains itself without indirection.
     Cycle(ErrorGuaranteed),
 }
 
@@ -242,11 +264,11 @@ impl<'tcx> LayoutError<'tcx> {
 
         use crate::fluent_generated::*;
         match self {
-            Unknown(_) => middle_unknown_layout,
-            SizeOverflow(_) => middle_values_too_big,
-            TooGeneric(_) => middle_too_generic,
-            NormalizationFailure(_, _) => middle_cannot_be_normalized,
-            Cycle(_) => middle_cycle,
+            Unknown(_) => middle_layout_unknown,
+            SizeOverflow(_) => middle_layout_size_overflow,
+            TooGeneric(_) => middle_layout_too_generic,
+            NormalizationFailure(_, _) => middle_layout_normalization_failure,
+            Cycle(_) => middle_layout_cycle,
             ReferencesError(_) => middle_layout_references_error,
         }
     }
@@ -275,7 +297,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
         match *self {
             LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"),
             LayoutError::TooGeneric(ty) => {
-                write!(f, "`{ty}` does not have a fixed size")
+                write!(f, "the type `{ty}` does not have a fixed layout")
             }
             LayoutError::SizeOverflow(ty) => {
                 write!(f, "values of the type `{ty}` are too big for the target architecture")
@@ -778,7 +800,7 @@ where
                     size: Size::ZERO,
                     max_repr_align: None,
                     unadjusted_abi_align: tcx.data_layout.i8_align.abi,
-                    randomization_seed: 0,
+                    randomization_seed: Hash64::ZERO,
                 })
             }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 52cb8f57a88..c52e774c8b7 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1470,7 +1470,7 @@ pub enum ImplTraitInTraitData {
 
 impl<'tcx> TyCtxt<'tcx> {
     pub fn typeck_body(self, body: hir::BodyId) -> &'tcx TypeckResults<'tcx> {
-        self.typeck(self.hir().body_owner_def_id(body))
+        self.typeck(self.hir_body_owner_def_id(body))
     }
 
     pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
@@ -1487,8 +1487,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         // Generate a deterministically-derived seed from the item's path hash
         // to allow for cross-crate compilation to actually work
-        let mut field_shuffle_seed =
-            self.def_path_hash(did.to_def_id()).0.to_smaller_hash().as_u64();
+        let mut field_shuffle_seed = self.def_path_hash(did.to_def_id()).0.to_smaller_hash();
 
         // If the user defined a custom seed for layout randomization, xor the item's
         // path hash with the user defined seed, this will allowing determinism while
@@ -2168,7 +2167,6 @@ pub fn provide(providers: &mut Providers) {
     util::provide(providers);
     print::provide(providers);
     super::util::bug::provide(providers);
-    super::middle::provide(providers);
     *providers = Providers {
         trait_impls_of: trait_def::trait_impls_of_provider,
         incoherent_impls: trait_def::incoherent_impls_provider,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 7166c284c3d..11b430dd358 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3299,13 +3299,12 @@ define_print_and_forward_display! {
 
 fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) {
     // Iterate all local crate items no matter where they are defined.
-    let hir = tcx.hir();
-    for id in hir.items() {
+    for id in tcx.hir_free_items() {
         if matches!(tcx.def_kind(id.owner_id), DefKind::Use) {
             continue;
         }
 
-        let item = hir.item(id);
+        let item = tcx.hir_item(id);
         if item.ident.name == kw::Empty {
             continue;
         }
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 743ea33b20a..17e90c15d41 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -235,7 +235,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
         }
     }
 
-    for &impl_def_id in tcx.hir().trait_impls(trait_id) {
+    for &impl_def_id in tcx.hir_trait_impls(trait_id) {
         let impl_def_id = impl_def_id.to_def_id();
 
         let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();
@@ -267,7 +267,7 @@ pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -
 
 pub(super) fn traits_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] {
     let mut traits = Vec::new();
-    for id in tcx.hir().items() {
+    for id in tcx.hir_free_items() {
         if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) {
             traits.push(id.owner_id.to_def_id())
         }
@@ -278,7 +278,7 @@ pub(super) fn traits_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] {
 
 pub(super) fn trait_impls_in_crate_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] {
     let mut trait_impls = Vec::new();
-    for id in tcx.hir().items() {
+    for id in tcx.hir_free_items() {
         if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. })
             && tcx.impl_trait_ref(id.owner_id).is_some()
         {
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 1b5b791bb24..b8c73d25843 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -147,9 +147,7 @@ pub struct TypeckResults<'tcx> {
     coercion_casts: ItemLocalSet,
 
     /// Set of trait imports actually used in the method resolution.
-    /// This is used for warning unused imports. During type
-    /// checking, this `Arc` should not be cloned: it must have a ref-count
-    /// of 1 so that we can insert things into the set mutably.
+    /// This is used for warning unused imports.
     pub used_trait_imports: UnordSet<LocalDefId>,
 
     /// If any errors occurred while type-checking this body,
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 94bd359f6eb..88d57498542 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -5,9 +5,10 @@ use std::{fmt, iter};
 use rustc_abi::{ExternAbi, Float, Integer, IntegerType, Size};
 use rustc_apfloat::Float as _;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorGuaranteed;
+use rustc_hashes::Hash128;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 433f7542bd7..9450ce7ec44 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -53,7 +53,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
         let arity = if let Some(frame) = cycle_error.cycle.get(0)
             && frame.query.dep_kind == dep_kinds::fn_sig
             && let Some(def_id) = frame.query.def_id
-            && let Some(node) = tcx.hir().get_if_local(def_id)
+            && let Some(node) = tcx.hir_get_if_local(def_id)
             && let Some(sig) = node.fn_sig()
         {
             sig.decl.inputs.len()
diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs
index eab414e150f..19669021eef 100644
--- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs
@@ -1,6 +1,5 @@
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty;
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index e04c70b5883..fb0aa354913 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -465,11 +465,10 @@ fn construct_fn<'tcx>(
     assert_eq!(expr.as_usize(), thir.exprs.len() - 1);
 
     // Figure out what primary body this item has.
-    let body = tcx.hir().body_owned_by(fn_def);
+    let body = tcx.hir_body_owned_by(fn_def);
     let span_with_body = tcx.hir().span_with_body(fn_id);
     let return_ty_span = tcx
-        .hir()
-        .fn_decl_by_hir_id(fn_id)
+        .hir_fn_decl_by_hir_id(fn_id)
         .unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", fn_def))
         .output
         .span();
@@ -758,7 +757,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         check_overflow |= tcx.sess.overflow_checks();
         // Constants always need overflow checks.
         check_overflow |= matches!(
-            tcx.hir().body_owner_kind(def),
+            tcx.hir_body_owner_kind(def),
             hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_)
         );
 
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 1bd33475e60..84f58f1968d 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -759,7 +759,7 @@ impl UnsafeOpKind {
         });
         let unsafe_not_inherited_note = if should_suggest {
             suggest_unsafe_block.then(|| {
-                let body_span = tcx.hir().body(parent_owner.body_id().unwrap()).value.span;
+                let body_span = tcx.hir_body(parent_owner.body_id().unwrap()).value.span;
                 UnsafeNotInheritedLintNote {
                     signature_span: tcx.def_span(parent_id.def_id),
                     body_span,
@@ -927,7 +927,7 @@ impl UnsafeOpKind {
                 && let hir::BlockCheckMode::UnsafeBlock(_) = block.rules
             {
                 true
-            } else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id)
+            } else if let Some(sig) = tcx.hir_fn_sig_by_hir_id(*id)
                 && matches!(sig.header.safety, hir::HeaderSafety::Normal(hir::Safety::Unsafe))
             {
                 true
@@ -1145,7 +1145,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
     let thir = &thir.steal();
 
     let hir_id = tcx.local_def_id_to_hir_id(def);
-    let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
+    let safety_context = tcx.hir_fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
         match fn_sig.header.safety {
             // We typeck the body as safe, but otherwise treat it as unsafe everywhere else.
             // Call sites to other SafeTargetFeatures functions are checked explicitly and don't need
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 07bdc59756a..f1753be845d 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -601,8 +601,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo
             let def_span = self
                 .cx
                 .tcx
-                .hir()
-                .get_if_local(def.did())
+                .hir_get_if_local(def.did())
                 .and_then(|node| node.ident())
                 .map(|ident| ident.span)
                 .unwrap_or_else(|| self.cx.tcx.def_span(def.did()));
@@ -1113,9 +1112,6 @@ pub(crate) struct Rust2024IncompatiblePatSugg {
     pub(crate) suggestion: Vec<(Span, String)>,
     pub(crate) ref_pattern_count: usize,
     pub(crate) binding_mode_count: usize,
-    /// Internal state: the ref-mutability of the default binding mode at the subpattern being
-    /// lowered, with the span where it was introduced. `None` for a by-value default mode.
-    pub(crate) default_mode_span: Option<(Span, ty::Mutability)>,
     /// Labels for where incompatibility-causing by-ref default binding modes were introduced.
     pub(crate) default_mode_labels: FxIndexMap<Span, ty::Mutability>,
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 54da6924db4..d0fca76fcf0 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -828,7 +828,6 @@ impl<'tcx> ThirBuildCx<'tcx> {
             },
             hir::ExprKind::Match(discr, arms, match_source) => ExprKind::Match {
                 scrutinee: self.mirror_expr(discr),
-                scrutinee_hir_id: discr.hir_id,
                 arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
                 match_source,
             },
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index a01609012b8..7a9f6e46304 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -22,8 +22,7 @@ pub(crate) fn thir_body(
     tcx: TyCtxt<'_>,
     owner_def: LocalDefId,
 ) -> Result<(&Steal<Thir<'_>>, ExprId), ErrorGuaranteed> {
-    let hir = tcx.hir();
-    let body = hir.body_owned_by(owner_def);
+    let body = tcx.hir_body_owned_by(owner_def);
     let mut cx = ThirBuildCx::new(tcx, owner_def);
     if let Some(reported) = cx.typeck_results.tainted_by_errors {
         return Err(reported);
@@ -31,7 +30,7 @@ pub(crate) fn thir_body(
     let expr = cx.mirror_expr(body.value);
 
     let owner_id = tcx.local_def_id_to_hir_id(owner_def);
-    if let Some(fn_decl) = hir.fn_decl_by_hir_id(owner_id) {
+    if let Some(fn_decl) = tcx.hir_fn_decl_by_hir_id(owner_id) {
         let closure_env_param = cx.closure_env_param(owner_def, owner_id);
         let explicit_params = cx.explicit_params(owner_id, fn_decl, &body);
         cx.thir.params = closure_env_param.into_iter().chain(explicit_params).collect();
@@ -77,7 +76,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
         let hir = tcx.hir();
         let hir_id = tcx.local_def_id_to_hir_id(def);
 
-        let body_type = if hir.body_owner_kind(def).is_fn_or_closure() {
+        let body_type = if tcx.hir_body_owner_kind(def).is_fn_or_closure() {
             // fetch the fully liberated fn signature (that is, all bound
             // types/lifetimes replaced)
             BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id])
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 697cb7cf37a..6dbb460d8b1 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -10,7 +10,6 @@ use rustc_hir::{self as hir, BindingMode, ByRef, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::Level;
 use rustc_middle::bug;
-use rustc_middle::middle::limits::get_limit_size;
 use rustc_middle::thir::visit::Visitor;
 use rustc_middle::thir::*;
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -25,7 +24,7 @@ use rustc_session::lint::builtin::{
 };
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::hygiene::DesugaringKind;
-use rustc_span::{Ident, Span, sym};
+use rustc_span::{Ident, Span};
 use rustc_trait_selection::infer::InferCtxtExt;
 use tracing::instrument;
 
@@ -152,7 +151,7 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
                 }
                 return;
             }
-            ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => {
+            ExprKind::Match { scrutinee, box ref arms, match_source } => {
                 self.check_match(scrutinee, arms, match_source, ex.span);
             }
             ExprKind::Let { box ref pat, expr } => {
@@ -404,18 +403,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         arms: &[MatchArm<'p, 'tcx>],
         scrut_ty: Ty<'tcx>,
     ) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
-        let pattern_complexity_limit =
-            get_limit_size(cx.tcx.hir().krate_attrs(), cx.tcx.sess, sym::pattern_complexity);
-        let report = rustc_pattern_analysis::rustc::analyze_match(
-            &cx,
-            &arms,
-            scrut_ty,
-            pattern_complexity_limit,
-        )
-        .map_err(|err| {
-            self.error = Err(err);
-            err
-        })?;
+        let report =
+            rustc_pattern_analysis::rustc::analyze_match(&cx, &arms, scrut_ty).map_err(|err| {
+                self.error = Err(err);
+                err
+            })?;
 
         // Warn unreachable subpatterns.
         for (arm, is_useful) in report.arm_usefulness.iter() {
@@ -1498,7 +1490,7 @@ fn report_adt_defined_here<'tcx>(
         return None;
     };
     let adt_def_span =
-        tcx.hir().get_if_local(def.did()).and_then(|node| node.ident()).map(|ident| ident.span);
+        tcx.hir_get_if_local(def.did()).and_then(|node| node.ident()).map(|ident| ident.span);
     let adt_def_span = if point_at_non_local_ty {
         adt_def_span.unwrap_or_else(|| tcx.def_span(def.did()))
     } else {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 551ec5cf4e9..667d59d858e 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -148,7 +148,7 @@ impl<'tcx> ConstToPat<'tcx> {
                     if let ty::GenericArgKind::Type(ty) = arg.unpack()
                         && let ty::Param(param_ty) = ty.kind()
                     {
-                        let def_id = self.tcx.hir().enclosing_body_owner(self.id);
+                        let def_id = self.tcx.hir_enclosing_body_owner(self.id);
                         let generics = self.tcx.generics_of(def_id);
                         let param = generics.type_param(*param_ty, self.tcx);
                         let span = self.tcx.def_span(param.def_id);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/migration.rs b/compiler/rustc_mir_build/src/thir/pattern/migration.rs
new file mode 100644
index 00000000000..bd7787b643d
--- /dev/null
+++ b/compiler/rustc_mir_build/src/thir/pattern/migration.rs
@@ -0,0 +1,182 @@
+//! Automatic migration of Rust 2021 patterns to a form valid in both Editions 2021 and 2024.
+
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_errors::MultiSpan;
+use rustc_hir::{BindingMode, ByRef, HirId, Mutability};
+use rustc_lint as lint;
+use rustc_middle::span_bug;
+use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, Ty, TyCtxt};
+use rustc_span::{Ident, Span};
+
+use crate::errors::{Rust2024IncompatiblePat, Rust2024IncompatiblePatSugg};
+use crate::fluent_generated as fluent;
+
+/// For patterns flagged for migration during HIR typeck, this handles constructing and emitting
+/// a diagnostic suggestion.
+pub(super) struct PatMigration<'a> {
+    suggestion: Vec<(Span, String)>,
+    ref_pattern_count: usize,
+    binding_mode_count: usize,
+    /// Internal state: the ref-mutability of the default binding mode at the subpattern being
+    /// lowered, with the span where it was introduced. `None` for a by-value default mode.
+    default_mode_span: Option<(Span, ty::Mutability)>,
+    /// Labels for where incompatibility-causing by-ref default binding modes were introduced.
+    // FIXME(ref_pat_eat_one_layer_2024_structural): To track the default binding mode, we duplicate
+    // logic from HIR typeck (in order to avoid needing to store all changes to the dbm in
+    // TypeckResults). Since the default binding mode acts differently under this feature gate, the
+    // labels will be wrong.
+    default_mode_labels: FxIndexMap<Span, Mutability>,
+    /// Information collected from typeck, including spans for subpatterns invalid in Rust 2024.
+    info: &'a Rust2024IncompatiblePatInfo,
+}
+
+impl<'a> PatMigration<'a> {
+    pub(super) fn new(info: &'a Rust2024IncompatiblePatInfo) -> Self {
+        PatMigration {
+            suggestion: Vec::new(),
+            ref_pattern_count: 0,
+            binding_mode_count: 0,
+            default_mode_span: None,
+            default_mode_labels: Default::default(),
+            info,
+        }
+    }
+
+    /// On Rust 2024, this emits a hard error. On earlier Editions, this emits the
+    /// future-incompatibility lint `rust_2024_incompatible_pat`.
+    pub(super) fn emit<'tcx>(self, tcx: TyCtxt<'tcx>, pat_id: HirId) {
+        let mut spans =
+            MultiSpan::from_spans(self.info.primary_labels.iter().map(|(span, _)| *span).collect());
+        for (span, label) in self.info.primary_labels.iter() {
+            spans.push_span_label(*span, label.clone());
+        }
+        let sugg = Rust2024IncompatiblePatSugg {
+            suggest_eliding_modes: self.info.suggest_eliding_modes,
+            suggestion: self.suggestion,
+            ref_pattern_count: self.ref_pattern_count,
+            binding_mode_count: self.binding_mode_count,
+            default_mode_labels: self.default_mode_labels,
+        };
+        // If a relevant span is from at least edition 2024, this is a hard error.
+        let is_hard_error = spans.primary_spans().iter().any(|span| span.at_least_rust_2024());
+        if is_hard_error {
+            let mut err =
+                tcx.dcx().struct_span_err(spans, fluent::mir_build_rust_2024_incompatible_pat);
+            if let Some(info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible {
+                // provide the same reference link as the lint
+                err.note(format!("for more information, see {}", info.reference));
+            }
+            err.arg("bad_modifiers", self.info.bad_modifiers);
+            err.arg("bad_ref_pats", self.info.bad_ref_pats);
+            err.arg("is_hard_error", true);
+            err.subdiagnostic(sugg);
+            err.emit();
+        } else {
+            tcx.emit_node_span_lint(
+                lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
+                pat_id,
+                spans,
+                Rust2024IncompatiblePat {
+                    sugg,
+                    bad_modifiers: self.info.bad_modifiers,
+                    bad_ref_pats: self.info.bad_ref_pats,
+                    is_hard_error,
+                },
+            );
+        }
+    }
+
+    /// Tracks when we're lowering a pattern that implicitly dereferences the scrutinee.
+    /// This should only be called when the pattern type adjustments list `adjustments` is
+    /// non-empty. Returns the prior default binding mode; this should be followed by a call to
+    /// [`PatMigration::leave_ref`] to restore it when we leave the pattern.
+    pub(super) fn visit_implicit_derefs<'tcx>(
+        &mut self,
+        pat_span: Span,
+        adjustments: &[Ty<'tcx>],
+    ) -> Option<(Span, Mutability)> {
+        let implicit_deref_mutbls = adjustments.iter().map(|ref_ty| {
+            let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
+                span_bug!(pat_span, "pattern implicitly dereferences a non-ref type");
+            };
+            mutbl
+        });
+
+        if !self.info.suggest_eliding_modes {
+            // If we can't fix the pattern by eliding modifiers, we'll need to make the pattern
+            // fully explicit. i.e. we'll need to suggest reference patterns for this.
+            let suggestion_str: String =
+                implicit_deref_mutbls.clone().map(|mutbl| mutbl.ref_prefix_str()).collect();
+            self.suggestion.push((pat_span.shrink_to_lo(), suggestion_str));
+            self.ref_pattern_count += adjustments.len();
+        }
+
+        // Remember if this changed the default binding mode, in case we want to label it.
+        let min_mutbl = implicit_deref_mutbls.min().unwrap();
+        if self.default_mode_span.is_none_or(|(_, old_mutbl)| min_mutbl < old_mutbl) {
+            // This changes the default binding mode to `ref` or `ref mut`. Return the old mode so
+            // it can be reinstated when we leave the pattern.
+            self.default_mode_span.replace((pat_span, min_mutbl))
+        } else {
+            // This does not change the default binding mode; it was already `ref` or `ref mut`.
+            self.default_mode_span
+        }
+    }
+
+    /// Tracks the default binding mode when we're lowering a `&` or `&mut` pattern.
+    /// Returns the prior default binding mode; this should be followed by a call to
+    /// [`PatMigration::leave_ref`] to restore it when we leave the pattern.
+    pub(super) fn visit_explicit_deref(&mut self) -> Option<(Span, Mutability)> {
+        if let Some((default_mode_span, default_ref_mutbl)) = self.default_mode_span {
+            // If this eats a by-ref default binding mode, label the binding mode.
+            self.default_mode_labels.insert(default_mode_span, default_ref_mutbl);
+        }
+        // Set the default binding mode to by-value and return the old default binding mode so it
+        // can be reinstated when we leave the pattern.
+        self.default_mode_span.take()
+    }
+
+    /// Restores the default binding mode after lowering a pattern that could change it.
+    /// This should follow a call to either [`PatMigration::visit_explicit_deref`] or
+    /// [`PatMigration::visit_implicit_derefs`].
+    pub(super) fn leave_ref(&mut self, old_mode_span: Option<(Span, Mutability)>) {
+        self.default_mode_span = old_mode_span
+    }
+
+    /// Determines if a binding is relevant to the diagnostic and adjusts the notes/suggestion if
+    /// so. Bindings are relevant if they have a modifier under a by-ref default mode (invalid in
+    /// Rust 2024) or if we need to suggest a binding modifier for them.
+    pub(super) fn visit_binding(
+        &mut self,
+        pat_span: Span,
+        mode: BindingMode,
+        explicit_ba: BindingMode,
+        ident: Ident,
+    ) {
+        if explicit_ba != BindingMode::NONE
+            && let Some((default_mode_span, default_ref_mutbl)) = self.default_mode_span
+        {
+            // If this overrides a by-ref default binding mode, label the binding mode.
+            self.default_mode_labels.insert(default_mode_span, default_ref_mutbl);
+            // If our suggestion is to elide redundnt modes, this will be one of them.
+            if self.info.suggest_eliding_modes {
+                self.suggestion.push((pat_span.with_hi(ident.span.lo()), String::new()));
+                self.binding_mode_count += 1;
+            }
+        }
+        if !self.info.suggest_eliding_modes
+            && explicit_ba.0 == ByRef::No
+            && let ByRef::Yes(mutbl) = mode.0
+        {
+            // If we can't fix the pattern by eliding modifiers, we'll need to make the pattern
+            // fully explicit. i.e. we'll need to suggest reference patterns for this.
+            let sugg_str = match mutbl {
+                Mutability::Not => "ref ",
+                Mutability::Mut => "ref mut ",
+            };
+            self.suggestion
+                .push((pat_span.with_lo(ident.span.lo()).shrink_to_lo(), sugg_str.to_owned()));
+            self.binding_mode_count += 1;
+        }
+    }
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 22b8bfef09d..8dc3f998e09 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -2,18 +2,17 @@
 
 mod check_match;
 mod const_to_pat;
+mod migration;
 
 use std::cmp::Ordering;
 use std::sync::Arc;
 
 use rustc_abi::{FieldIdx, Integer};
-use rustc_errors::MultiSpan;
 use rustc_errors::codes::*;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
-use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd};
+use rustc_hir::{self as hir, RangeEnd};
 use rustc_index::Idx;
-use rustc_lint as lint;
 use rustc_middle::mir::interpret::LitToConstInput;
 use rustc_middle::thir::{
     Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
@@ -26,8 +25,8 @@ use rustc_span::{ErrorGuaranteed, Span};
 use tracing::{debug, instrument};
 
 pub(crate) use self::check_match::check_match;
+use self::migration::PatMigration;
 use crate::errors::*;
-use crate::fluent_generated as fluent;
 
 struct PatCtxt<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -35,7 +34,7 @@ struct PatCtxt<'a, 'tcx> {
     typeck_results: &'a ty::TypeckResults<'tcx>,
 
     /// Used by the Rust 2024 migration lint.
-    rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg>,
+    rust_2024_migration: Option<PatMigration<'a>>,
 }
 
 pub(super) fn pat_from_hir<'a, 'tcx>(
@@ -44,59 +43,19 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
     typeck_results: &'a ty::TypeckResults<'tcx>,
     pat: &'tcx hir::Pat<'tcx>,
 ) -> Box<Pat<'tcx>> {
-    let migration_info = typeck_results.rust_2024_migration_desugared_pats().get(pat.hir_id);
     let mut pcx = PatCtxt {
         tcx,
         typing_env,
         typeck_results,
-        rust_2024_migration_suggestion: migration_info.and_then(|info| {
-            Some(Rust2024IncompatiblePatSugg {
-                suggest_eliding_modes: info.suggest_eliding_modes,
-                suggestion: Vec::new(),
-                ref_pattern_count: 0,
-                binding_mode_count: 0,
-                default_mode_span: None,
-                default_mode_labels: Default::default(),
-            })
-        }),
+        rust_2024_migration: typeck_results
+            .rust_2024_migration_desugared_pats()
+            .get(pat.hir_id)
+            .map(PatMigration::new),
     };
     let result = pcx.lower_pattern(pat);
     debug!("pat_from_hir({:?}) = {:?}", pat, result);
-    if let Some(info) = migration_info
-        && let Some(sugg) = pcx.rust_2024_migration_suggestion
-    {
-        let mut spans =
-            MultiSpan::from_spans(info.primary_labels.iter().map(|(span, _)| *span).collect());
-        for (span, label) in &info.primary_labels {
-            spans.push_span_label(*span, label.clone());
-        }
-        // If a relevant span is from at least edition 2024, this is a hard error.
-        let is_hard_error = spans.primary_spans().iter().any(|span| span.at_least_rust_2024());
-        if is_hard_error {
-            let mut err =
-                tcx.dcx().struct_span_err(spans, fluent::mir_build_rust_2024_incompatible_pat);
-            if let Some(lint_info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible {
-                // provide the same reference link as the lint
-                err.note(format!("for more information, see {}", lint_info.reference));
-            }
-            err.arg("bad_modifiers", info.bad_modifiers);
-            err.arg("bad_ref_pats", info.bad_ref_pats);
-            err.arg("is_hard_error", true);
-            err.subdiagnostic(sugg);
-            err.emit();
-        } else {
-            tcx.emit_node_span_lint(
-                lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
-                pat.hir_id,
-                spans,
-                Rust2024IncompatiblePat {
-                    sugg,
-                    bad_modifiers: info.bad_modifiers,
-                    bad_ref_pats: info.bad_ref_pats,
-                    is_hard_error,
-                },
-            );
-        }
+    if let Some(m) = pcx.rust_2024_migration {
+        m.emit(tcx, pat.hir_id);
     }
     result
 }
@@ -106,31 +65,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         let adjustments: &[Ty<'tcx>] =
             self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
 
+        // Track the default binding mode for the Rust 2024 migration suggestion.
         let mut opt_old_mode_span = None;
-        if let Some(s) = &mut self.rust_2024_migration_suggestion
+        if let Some(s) = &mut self.rust_2024_migration
             && !adjustments.is_empty()
         {
-            let implicit_deref_mutbls = adjustments.iter().map(|ref_ty| {
-                let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
-                    span_bug!(pat.span, "pattern implicitly dereferences a non-ref type");
-                };
-                mutbl
-            });
-
-            if !s.suggest_eliding_modes {
-                let suggestion_str: String =
-                    implicit_deref_mutbls.clone().map(|mutbl| mutbl.ref_prefix_str()).collect();
-                s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str));
-                s.ref_pattern_count += adjustments.len();
-            }
-
-            // Remember if this changed the default binding mode, in case we want to label it.
-            let min_mutbl = implicit_deref_mutbls.min().unwrap();
-            if s.default_mode_span.is_none_or(|(_, old_mutbl)| min_mutbl < old_mutbl) {
-                opt_old_mode_span = Some(s.default_mode_span);
-                s.default_mode_span = Some((pat.span, min_mutbl));
-            }
-        };
+            opt_old_mode_span = s.visit_implicit_derefs(pat.span, adjustments);
+        }
 
         // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
         // pattern has the type that results *after* dereferencing. For example, in this code:
@@ -169,10 +110,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             })
         });
 
-        if let Some(s) = &mut self.rust_2024_migration_suggestion
-            && let Some(old_mode_span) = opt_old_mode_span
+        if let Some(s) = &mut self.rust_2024_migration
+            && !adjustments.is_empty()
         {
-            s.default_mode_span = old_mode_span;
+            s.leave_ref(opt_old_mode_span);
         }
 
         adjusted_pat
@@ -368,16 +309,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
             hir::PatKind::Ref(subpattern, _) => {
                 // Track the default binding mode for the Rust 2024 migration suggestion.
-                let old_mode_span = self.rust_2024_migration_suggestion.as_mut().and_then(|s| {
-                    if let Some((default_mode_span, default_ref_mutbl)) = s.default_mode_span {
-                        // If this eats a by-ref default binding mode, label the binding mode.
-                        s.default_mode_labels.insert(default_mode_span, default_ref_mutbl);
-                    }
-                    s.default_mode_span.take()
-                });
+                let opt_old_mode_span =
+                    self.rust_2024_migration.as_mut().and_then(|s| s.visit_explicit_deref());
                 let subpattern = self.lower_pattern(subpattern);
-                if let Some(s) = &mut self.rust_2024_migration_suggestion {
-                    s.default_mode_span = old_mode_span;
+                if let Some(s) = &mut self.rust_2024_migration {
+                    s.leave_ref(opt_old_mode_span);
                 }
                 PatKind::Deref { subpattern }
             }
@@ -408,32 +344,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     .get(pat.hir_id)
                     .expect("missing binding mode");
 
-                if let Some(s) = &mut self.rust_2024_migration_suggestion {
-                    if explicit_ba != hir::BindingMode::NONE
-                        && let Some((default_mode_span, default_ref_mutbl)) = s.default_mode_span
-                    {
-                        // If this overrides a by-ref default binding mode, label the binding mode.
-                        s.default_mode_labels.insert(default_mode_span, default_ref_mutbl);
-                        // If our suggestion is to elide redundnt modes, this will be one of them.
-                        if s.suggest_eliding_modes {
-                            s.suggestion.push((pat.span.with_hi(ident.span.lo()), String::new()));
-                            s.binding_mode_count += 1;
-                        }
-                    }
-                    if !s.suggest_eliding_modes
-                        && explicit_ba.0 == ByRef::No
-                        && let ByRef::Yes(mutbl) = mode.0
-                    {
-                        let sugg_str = match mutbl {
-                            Mutability::Not => "ref ",
-                            Mutability::Mut => "ref mut ",
-                        };
-                        s.suggestion.push((
-                            pat.span.with_lo(ident.span.lo()).shrink_to_lo(),
-                            sugg_str.to_owned(),
-                        ));
-                        s.binding_mode_count += 1;
-                    }
+                if let Some(s) = &mut self.rust_2024_migration {
+                    s.visit_binding(pat.span, mode, explicit_ba, ident);
                 }
 
                 // A ref x pattern is the same node used for x, and as such it has
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 07517d7edab..3d7f9e2d8e7 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -1,9 +1,11 @@
 use std::ops::RangeInclusive;
 
-use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges};
+use rustc_middle::mir::{
+    self, BasicBlock, CallReturnPlaces, Location, SwitchTargetValue, TerminatorEdges,
+};
 
 use super::visitor::ResultsVisitor;
-use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget};
+use super::{Analysis, Effect, EffectIndex, Results};
 
 pub trait Direction {
     const IS_FORWARD: bool;
@@ -112,14 +114,10 @@ impl Direction for Backward {
 
                 mir::TerminatorKind::SwitchInt { targets: _, ref discr } => {
                     if let Some(mut data) = analysis.get_switch_int_data(block, discr) {
-                        let values = &body.basic_blocks.switch_sources()[&(block, pred)];
-                        let targets =
-                            values.iter().map(|&value| SwitchIntTarget { value, target: block });
-
                         let mut tmp = analysis.bottom_value(body);
-                        for target in targets {
-                            tmp.clone_from(&exit_state);
-                            analysis.apply_switch_int_edge_effect(&mut data, &mut tmp, target);
+                        for &value in &body.basic_blocks.switch_sources()[&(block, pred)] {
+                            tmp.clone_from(exit_state);
+                            analysis.apply_switch_int_edge_effect(&mut data, &mut tmp, value);
                             propagate(pred, &tmp);
                         }
                     } else {
@@ -292,12 +290,9 @@ impl Direction for Forward {
                 if let Some(mut data) = analysis.get_switch_int_data(block, discr) {
                     let mut tmp = analysis.bottom_value(body);
                     for (value, target) in targets.iter() {
-                        tmp.clone_from(&exit_state);
-                        analysis.apply_switch_int_edge_effect(
-                            &mut data,
-                            &mut tmp,
-                            SwitchIntTarget { value: Some(value), target },
-                        );
+                        tmp.clone_from(exit_state);
+                        let value = SwitchTargetValue::Normal(value);
+                        analysis.apply_switch_int_edge_effect(&mut data, &mut tmp, value);
                         propagate(target, &tmp);
                     }
 
@@ -308,7 +303,7 @@ impl Direction for Forward {
                     analysis.apply_switch_int_edge_effect(
                         &mut data,
                         exit_state,
-                        SwitchIntTarget { value: None, target: otherwise },
+                        SwitchTargetValue::Otherwise,
                     );
                     propagate(otherwise, exit_state);
                 } else {
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 60c5cb0cae8..09f6cdb5c4a 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -38,7 +38,9 @@ use rustc_data_structures::work_queue::WorkQueue;
 use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::bug;
-use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal};
+use rustc_middle::mir::{
+    self, BasicBlock, CallReturnPlaces, Location, SwitchTargetValue, TerminatorEdges, traversal,
+};
 use rustc_middle::ty::TyCtxt;
 use tracing::error;
 
@@ -220,7 +222,7 @@ pub trait Analysis<'tcx> {
         &mut self,
         _data: &mut Self::SwitchIntData,
         _state: &mut Self::Domain,
-        _edge: SwitchIntTarget,
+        _value: SwitchTargetValue,
     ) {
         unreachable!();
     }
@@ -430,10 +432,5 @@ impl EffectIndex {
     }
 }
 
-pub struct SwitchIntTarget {
-    pub value: Option<u128>,
-    pub target: BasicBlock,
-}
-
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
index 3be450a0b3f..f5ffc42d52a 100644
--- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
@@ -4,13 +4,14 @@ use rustc_abi::VariantIdx;
 use rustc_index::Idx;
 use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
 use rustc_middle::bug;
-use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdges};
+use rustc_middle::mir::{
+    self, Body, CallReturnPlaces, Location, SwitchTargetValue, TerminatorEdges,
+};
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::{self, TyCtxt};
 use tracing::{debug, instrument};
 
 use crate::drop_flag_effects::DropFlagState;
-use crate::framework::SwitchIntTarget;
 use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
 use crate::{
     Analysis, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry,
@@ -422,9 +423,9 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
         &mut self,
         data: &mut Self::SwitchIntData,
         state: &mut Self::Domain,
-        edge: SwitchIntTarget,
+        value: SwitchTargetValue,
     ) {
-        if let Some(value) = edge.value {
+        if let SwitchTargetValue::Normal(value) = value {
             // Kill all move paths that correspond to variants we know to be inactive along this
             // particular outgoing edge of a `SwitchInt`.
             drop_flag_effects::on_all_inactive_variants(
@@ -535,9 +536,9 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
         &mut self,
         data: &mut Self::SwitchIntData,
         state: &mut Self::Domain,
-        edge: SwitchIntTarget,
+        value: SwitchTargetValue,
     ) {
-        if let Some(value) = edge.value {
+        if let SwitchTargetValue::Normal(value) = value {
             // Mark all move paths that correspond to variants other than this one as maybe
             // uninitialized (in reality, they are *definitely* uninitialized).
             drop_flag_effects::on_all_inactive_variants(
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index b6c259aa4e0..8bbc89fdcec 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -1,7 +1,6 @@
 use std::mem;
 
 use rustc_index::IndexVec;
-use rustc_middle::mir::tcx::{PlaceTy, RvalueInitializationState};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::{bug, span_bug};
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index a51af8c40fd..104a2e8c091 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -7,7 +7,6 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_index::IndexVec;
 use rustc_index::bit_set::DenseBitSet;
-use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
diff --git a/compiler/rustc_mir_transform/src/check_inline.rs b/compiler/rustc_mir_transform/src/check_inline.rs
index 497f4a660ea..83c3cda5a50 100644
--- a/compiler/rustc_mir_transform/src/check_inline.rs
+++ b/compiler/rustc_mir_transform/src/check_inline.rs
@@ -16,7 +16,7 @@ pub(super) struct CheckForceInline;
 impl<'tcx> MirLint<'tcx> for CheckForceInline {
     fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         let def_id = body.source.def_id();
-        if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() {
+        if !tcx.hir_body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() {
             return;
         }
         let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else {
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index afc49c5cc54..f3f3a65cd80 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -393,12 +393,13 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
 
     fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
         // Remove StorageLive and StorageDead statements for remapped locals
-        data.retain_statements(|s| match s.kind {
-            StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
-                !self.remap.contains(l)
+        for s in &mut data.statements {
+            if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = s.kind
+                && self.remap.contains(l)
+            {
+                s.make_nop();
             }
-            _ => true,
-        });
+        }
 
         let ret_val = match data.terminator().kind {
             TerminatorKind::Return => {
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index e195681bc92..264995efe8f 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -10,7 +10,6 @@ mod unexpand;
 
 use rustc_hir as hir;
 use rustc_hir::intravisit::{Visitor, walk_expr};
-use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::coverage::{
     CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind,
@@ -291,7 +290,7 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
 
     let hir_node = tcx.hir_node_by_def_id(def_id);
     let fn_body_id = hir_node.body_id().expect("HIR node is a function with body");
-    let hir_body = tcx.hir().body(fn_body_id);
+    let hir_body = tcx.hir_body(fn_body_id);
 
     let maybe_fn_sig = hir_node.fn_sig();
     let is_async_fn = maybe_fn_sig.is_some_and(|fn_sig| fn_sig.header.is_async());
@@ -348,7 +347,7 @@ fn extract_hole_spans_from_hir<'tcx>(
     hir_body: &hir::Body<'tcx>,
 ) -> Vec<Span> {
     struct HolesVisitor<'hir, F> {
-        hir: Map<'hir>,
+        tcx: TyCtxt<'hir>,
         visit_hole_span: F,
     }
 
@@ -360,8 +359,8 @@ fn extract_hole_spans_from_hir<'tcx>(
         ///   items contained within them.
         type NestedFilter = nested_filter::All;
 
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.hir
+        fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+            self.tcx
         }
 
         fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
@@ -388,7 +387,7 @@ fn extract_hole_spans_from_hir<'tcx>(
 
     let mut hole_spans = vec![];
     let mut visitor = HolesVisitor {
-        hir: tcx.hir(),
+        tcx,
         visit_hole_span: |hole_span| {
             // Discard any holes that aren't directly visible within the body span.
             if body_span.contains(hole_span) && body_span.eq_ctxt(hole_span) {
diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs
index 2de55e38052..9330a9481f5 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drop.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs
@@ -185,7 +185,7 @@ where
             place.ty(self.elaborator.body(), self.tcx()).ty
         } else {
             // We don't have a slice with all the locals, since some are in the patch.
-            tcx::PlaceTy::from_ty(self.elaborator.patch_ref().local_ty(place.local))
+            PlaceTy::from_ty(self.elaborator.patch_ref().local_ty(place.local))
                 .multi_projection_ty(self.elaborator.tcx(), place.projection)
                 .ty
         }
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index ab6aafab446..530c72ca549 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -417,7 +417,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
                 ..
             } = data.terminator().kind
             {
-                assert!(!self.patch.is_patched(bb));
+                assert!(!self.patch.is_term_patched(bb));
 
                 let loc = Location { block: tgt, statement_index: 0 };
                 let path = self.move_data().rev_lookup.find(destination.as_ref());
@@ -462,7 +462,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
                             // a Goto; see `MirPatch::new`).
                         }
                         _ => {
-                            assert!(!self.patch.is_patched(bb));
+                            assert!(!self.patch.is_term_patched(bb));
                         }
                     }
                 }
@@ -486,7 +486,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
                 ..
             } = data.terminator().kind
             {
-                assert!(!self.patch.is_patched(bb));
+                assert!(!self.patch.is_term_patched(bb));
 
                 let loc = Location { block: bb, statement_index: data.statements.len() };
                 let path = self.move_data().rev_lookup.find(destination.as_ref());
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index 9a6a153c7ba..5d21d687a35 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -113,7 +113,7 @@ fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option<PanicStrate
         return Some(PanicStrategy::Abort);
     }
 
-    for def_id in tcx.hir().body_owners() {
+    for def_id in tcx.hir_body_owners() {
         if tcx.has_ffi_unwind_calls(def_id) {
             // Given that this crate is compiled in `-C panic=unwind`, the `AbortUnwindingCalls`
             // MIR pass will not be run on FFI-unwind call sites, therefore a foreign exception
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 1f8392b2118..5981b5031c6 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -463,7 +463,7 @@ fn inline<'tcx, T: Inliner<'tcx>>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> b
     let def_id = body.source.def_id();
 
     // Only do inlining into fn bodies.
-    if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() {
+    if !tcx.hir_body_owner_kind(def_id).is_fn_or_closure() {
         return false;
     }
 
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 3dc4edaaa5a..da346dfc48c 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -36,7 +36,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
             typing_env: body.typing_env(tcx),
         };
         let preserve_ub_checks =
-            attr::contains_name(tcx.hir().krate_attrs(), sym::rustc_preserve_ub_checks);
+            attr::contains_name(tcx.hir_krate_attrs(), sym::rustc_preserve_ub_checks);
         for block in body.basic_blocks.as_mut() {
             for statement in block.statements.iter_mut() {
                 match statement.kind {
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index 1e546bfbeb3..47cb478fe33 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -6,6 +6,8 @@ use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_session::Session;
 
+use crate::patch::MirPatch;
+
 /// A pass that seeks to optimize unnecessary moves of large enum types, if there is a large
 /// enough discrepancy between them.
 ///
@@ -41,31 +43,34 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
         let mut alloc_cache = FxHashMap::default();
         let typing_env = body.typing_env(tcx);
 
-        let blocks = body.basic_blocks.as_mut();
-        let local_decls = &mut body.local_decls;
+        let mut patch = MirPatch::new(body);
 
-        for bb in blocks {
-            bb.expand_statements(|st| {
+        for (block, data) in body.basic_blocks.as_mut().iter_enumerated_mut() {
+            for (statement_index, st) in data.statements.iter_mut().enumerate() {
                 let StatementKind::Assign(box (
                     lhs,
                     Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
                 )) = &st.kind
                 else {
-                    return None;
+                    continue;
                 };
 
-                let ty = lhs.ty(local_decls, tcx).ty;
+                let location = Location { block, statement_index };
 
-                let (adt_def, num_variants, alloc_id) =
-                    self.candidate(tcx, typing_env, ty, &mut alloc_cache)?;
+                let ty = lhs.ty(&body.local_decls, tcx).ty;
 
-                let source_info = st.source_info;
-                let span = source_info.span;
+                let Some((adt_def, num_variants, alloc_id)) =
+                    self.candidate(tcx, typing_env, ty, &mut alloc_cache)
+                else {
+                    continue;
+                };
+
+                let span = st.source_info.span;
 
                 let tmp_ty = Ty::new_array(tcx, tcx.types.usize, num_variants as u64);
-                let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span));
-                let store_live =
-                    Statement { source_info, kind: StatementKind::StorageLive(size_array_local) };
+                let size_array_local = patch.new_temp(tmp_ty, span);
+
+                let store_live = StatementKind::StorageLive(size_array_local);
 
                 let place = Place::from(size_array_local);
                 let constant_vals = ConstOperand {
@@ -77,108 +82,63 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
                     ),
                 };
                 let rval = Rvalue::Use(Operand::Constant(Box::new(constant_vals)));
-                let const_assign =
-                    Statement { source_info, kind: StatementKind::Assign(Box::new((place, rval))) };
-
-                let discr_place = Place::from(
-                    local_decls.push(LocalDecl::new(adt_def.repr().discr_type().to_ty(tcx), span)),
-                );
-                let store_discr = Statement {
-                    source_info,
-                    kind: StatementKind::Assign(Box::new((
-                        discr_place,
-                        Rvalue::Discriminant(*rhs),
-                    ))),
-                };
-
-                let discr_cast_place =
-                    Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
-                let cast_discr = Statement {
-                    source_info,
-                    kind: StatementKind::Assign(Box::new((
-                        discr_cast_place,
-                        Rvalue::Cast(
-                            CastKind::IntToInt,
-                            Operand::Copy(discr_place),
-                            tcx.types.usize,
-                        ),
-                    ))),
-                };
-
-                let size_place =
-                    Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
-                let store_size = Statement {
-                    source_info,
-                    kind: StatementKind::Assign(Box::new((
-                        size_place,
-                        Rvalue::Use(Operand::Copy(Place {
-                            local: size_array_local,
-                            projection: tcx
-                                .mk_place_elems(&[PlaceElem::Index(discr_cast_place.local)]),
-                        })),
-                    ))),
-                };
-
-                let dst =
-                    Place::from(local_decls.push(LocalDecl::new(Ty::new_mut_ptr(tcx, ty), span)));
-                let dst_ptr = Statement {
-                    source_info,
-                    kind: StatementKind::Assign(Box::new((
-                        dst,
-                        Rvalue::RawPtr(RawPtrKind::Mut, *lhs),
-                    ))),
-                };
+                let const_assign = StatementKind::Assign(Box::new((place, rval)));
+
+                let discr_place =
+                    Place::from(patch.new_temp(adt_def.repr().discr_type().to_ty(tcx), span));
+                let store_discr =
+                    StatementKind::Assign(Box::new((discr_place, Rvalue::Discriminant(*rhs))));
+
+                let discr_cast_place = Place::from(patch.new_temp(tcx.types.usize, span));
+                let cast_discr = StatementKind::Assign(Box::new((
+                    discr_cast_place,
+                    Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr_place), tcx.types.usize),
+                )));
+
+                let size_place = Place::from(patch.new_temp(tcx.types.usize, span));
+                let store_size = StatementKind::Assign(Box::new((
+                    size_place,
+                    Rvalue::Use(Operand::Copy(Place {
+                        local: size_array_local,
+                        projection: tcx.mk_place_elems(&[PlaceElem::Index(discr_cast_place.local)]),
+                    })),
+                )));
+
+                let dst = Place::from(patch.new_temp(Ty::new_mut_ptr(tcx, ty), span));
+                let dst_ptr =
+                    StatementKind::Assign(Box::new((dst, Rvalue::RawPtr(RawPtrKind::Mut, *lhs))));
 
                 let dst_cast_ty = Ty::new_mut_ptr(tcx, tcx.types.u8);
-                let dst_cast_place =
-                    Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span)));
-                let dst_cast = Statement {
-                    source_info,
-                    kind: StatementKind::Assign(Box::new((
-                        dst_cast_place,
-                        Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty),
-                    ))),
-                };
+                let dst_cast_place = Place::from(patch.new_temp(dst_cast_ty, span));
+                let dst_cast = StatementKind::Assign(Box::new((
+                    dst_cast_place,
+                    Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty),
+                )));
 
-                let src =
-                    Place::from(local_decls.push(LocalDecl::new(Ty::new_imm_ptr(tcx, ty), span)));
-                let src_ptr = Statement {
-                    source_info,
-                    kind: StatementKind::Assign(Box::new((
-                        src,
-                        Rvalue::RawPtr(RawPtrKind::Const, *rhs),
-                    ))),
-                };
+                let src = Place::from(patch.new_temp(Ty::new_imm_ptr(tcx, ty), span));
+                let src_ptr =
+                    StatementKind::Assign(Box::new((src, Rvalue::RawPtr(RawPtrKind::Const, *rhs))));
 
                 let src_cast_ty = Ty::new_imm_ptr(tcx, tcx.types.u8);
-                let src_cast_place =
-                    Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span)));
-                let src_cast = Statement {
-                    source_info,
-                    kind: StatementKind::Assign(Box::new((
-                        src_cast_place,
-                        Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty),
-                    ))),
-                };
+                let src_cast_place = Place::from(patch.new_temp(src_cast_ty, span));
+                let src_cast = StatementKind::Assign(Box::new((
+                    src_cast_place,
+                    Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty),
+                )));
 
-                let deinit_old =
-                    Statement { source_info, kind: StatementKind::Deinit(Box::new(dst)) };
-
-                let copy_bytes = Statement {
-                    source_info,
-                    kind: StatementKind::Intrinsic(Box::new(
-                        NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
-                            src: Operand::Copy(src_cast_place),
-                            dst: Operand::Copy(dst_cast_place),
-                            count: Operand::Copy(size_place),
-                        }),
-                    )),
-                };
+                let deinit_old = StatementKind::Deinit(Box::new(dst));
+
+                let copy_bytes = StatementKind::Intrinsic(Box::new(
+                    NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
+                        src: Operand::Copy(src_cast_place),
+                        dst: Operand::Copy(dst_cast_place),
+                        count: Operand::Copy(size_place),
+                    }),
+                ));
 
-                let store_dead =
-                    Statement { source_info, kind: StatementKind::StorageDead(size_array_local) };
+                let store_dead = StatementKind::StorageDead(size_array_local);
 
-                let iter = [
+                let stmts = [
                     store_live,
                     const_assign,
                     store_discr,
@@ -191,14 +151,16 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
                     deinit_old,
                     copy_bytes,
                     store_dead,
-                ]
-                .into_iter();
+                ];
+                for stmt in stmts {
+                    patch.add_statement(location, stmt);
+                }
 
                 st.make_nop();
-
-                Some(iter)
-            });
+            }
         }
+
+        patch.apply(body);
     }
 
     fn is_required(&self) -> bool {
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 46abdcb2a87..04c9375b831 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -314,11 +314,11 @@ fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
 /// MIR associated with them.
 fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
     // All body-owners have MIR associated with them.
-    let mut set: FxIndexSet<_> = tcx.hir().body_owners().collect();
+    let mut set: FxIndexSet<_> = tcx.hir_body_owners().collect();
 
     // Coroutine-closures (e.g. async closures) have an additional by-move MIR
     // body that isn't in the HIR.
-    for body_owner in tcx.hir().body_owners() {
+    for body_owner in tcx.hir_body_owners() {
         if let DefKind::Closure = tcx.def_kind(body_owner)
             && tcx.needs_coroutine_by_move_body_def_id(body_owner.to_def_id())
         {
@@ -470,7 +470,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
     }
 
     let body = tcx.mir_drops_elaborated_and_const_checked(def);
-    let body = match tcx.hir().body_const_context(def) {
+    let body = match tcx.hir_body_const_context(def) {
         // consts and statics do not have `optimized_mir`, so we can steal the body instead of
         // cloning it.
         Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => body.steal(),
@@ -729,7 +729,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
         return shim::build_adt_ctor(tcx, did.to_def_id());
     }
 
-    match tcx.hir().body_const_context(did) {
+    match tcx.hir_body_const_context(did) {
         // Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked`
         // which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it
         // computes and caches its result.
diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs
index b4f6fa514a4..d3d181f6cb2 100644
--- a/compiler/rustc_mir_transform/src/patch.rs
+++ b/compiler/rustc_mir_transform/src/patch.rs
@@ -4,11 +4,12 @@ use rustc_middle::ty::Ty;
 use rustc_span::Span;
 use tracing::debug;
 
-/// This struct represents a patch to MIR, which can add
-/// new statements and basic blocks and patch over block
-/// terminators.
+/// This struct lets you "patch" a MIR body, i.e. modify it. You can queue up
+/// various changes, such as the addition of new statements and basic blocks
+/// and replacement of terminators, and then apply the queued changes all at
+/// once with `apply`. This is useful for MIR transformation passes.
 pub(crate) struct MirPatch<'tcx> {
-    patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>,
+    term_patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>,
     new_blocks: Vec<BasicBlockData<'tcx>>,
     new_statements: Vec<(Location, StatementKind<'tcx>)>,
     new_locals: Vec<LocalDecl<'tcx>>,
@@ -24,9 +25,10 @@ pub(crate) struct MirPatch<'tcx> {
 }
 
 impl<'tcx> MirPatch<'tcx> {
+    /// Creates a new, empty patch.
     pub(crate) fn new(body: &Body<'tcx>) -> Self {
         let mut result = MirPatch {
-            patch_map: IndexVec::from_elem(None, &body.basic_blocks),
+            term_patch_map: IndexVec::from_elem(None, &body.basic_blocks),
             new_blocks: vec![],
             new_statements: vec![],
             new_locals: vec![],
@@ -141,10 +143,12 @@ impl<'tcx> MirPatch<'tcx> {
         bb
     }
 
-    pub(crate) fn is_patched(&self, bb: BasicBlock) -> bool {
-        self.patch_map[bb].is_some()
+    /// Has a replacement of this block's terminator been queued in this patch?
+    pub(crate) fn is_term_patched(&self, bb: BasicBlock) -> bool {
+        self.term_patch_map[bb].is_some()
     }
 
+    /// Queues the addition of a new temporary with additional local info.
     pub(crate) fn new_local_with_info(
         &mut self,
         ty: Ty<'tcx>,
@@ -159,6 +163,7 @@ impl<'tcx> MirPatch<'tcx> {
         Local::new(index)
     }
 
+    /// Queues the addition of a new temporary.
     pub(crate) fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
         let index = self.next_local;
         self.next_local += 1;
@@ -174,29 +179,46 @@ impl<'tcx> MirPatch<'tcx> {
         self.new_locals[new_local_idx].ty
     }
 
+    /// Queues the addition of a new basic block.
     pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
-        let block = BasicBlock::new(self.patch_map.len());
+        let block = BasicBlock::new(self.term_patch_map.len());
         debug!("MirPatch: new_block: {:?}: {:?}", block, data);
         self.new_blocks.push(data);
-        self.patch_map.push(None);
+        self.term_patch_map.push(None);
         block
     }
 
+    /// Queues the replacement of a block's terminator.
     pub(crate) fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) {
-        assert!(self.patch_map[block].is_none());
+        assert!(self.term_patch_map[block].is_none());
         debug!("MirPatch: patch_terminator({:?}, {:?})", block, new);
-        self.patch_map[block] = Some(new);
+        self.term_patch_map[block] = Some(new);
     }
 
+    /// Queues the insertion of a statement at a given location. The statement
+    /// currently at that location, and all statements that follow, are shifted
+    /// down. If multiple statements are queued for addition at the same
+    /// location, the final statement order after calling `apply` will match
+    /// the queue insertion order.
+    ///
+    /// E.g. if we have `s0` at location `loc` and do these calls:
+    ///
+    ///   p.add_statement(loc, s1);
+    ///   p.add_statement(loc, s2);
+    ///   p.apply(body);
+    ///
+    /// then the final order will be `s1, s2, s0`, with `s1` at `loc`.
     pub(crate) fn add_statement(&mut self, loc: Location, stmt: StatementKind<'tcx>) {
         debug!("MirPatch: add_statement({:?}, {:?})", loc, stmt);
         self.new_statements.push((loc, stmt));
     }
 
+    /// Like `add_statement`, but specialized for assignments.
     pub(crate) fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
         self.add_statement(loc, StatementKind::Assign(Box::new((place, rv))));
     }
 
+    /// Applies the queued changes.
     pub(crate) fn apply(self, body: &mut Body<'tcx>) {
         debug!(
             "MirPatch: {:?} new temps, starting from index {}: {:?}",
@@ -209,14 +231,14 @@ impl<'tcx> MirPatch<'tcx> {
             self.new_blocks.len(),
             body.basic_blocks.len()
         );
-        let bbs = if self.patch_map.is_empty() && self.new_blocks.is_empty() {
+        let bbs = if self.term_patch_map.is_empty() && self.new_blocks.is_empty() {
             body.basic_blocks.as_mut_preserves_cfg()
         } else {
             body.basic_blocks.as_mut()
         };
         bbs.extend(self.new_blocks);
         body.local_decls.extend(self.new_locals);
-        for (src, patch) in self.patch_map.into_iter_enumerated() {
+        for (src, patch) in self.term_patch_map.into_iter_enumerated() {
             if let Some(patch) = patch {
                 debug!("MirPatch: patching block {:?}", src);
                 bbs[src].terminator_mut().kind = patch;
@@ -224,6 +246,9 @@ impl<'tcx> MirPatch<'tcx> {
         }
 
         let mut new_statements = self.new_statements;
+
+        // This must be a stable sort to provide the ordering described in the
+        // comment for `add_statement`.
         new_statements.sort_by_key(|s| s.0);
 
         let mut delta = 0;
diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs
index c5e951eb8b2..02caa92ad3f 100644
--- a/compiler/rustc_mir_transform/src/single_use_consts.rs
+++ b/compiler/rustc_mir_transform/src/single_use_consts.rs
@@ -48,9 +48,11 @@ impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
 
             // We're only changing an operand, not the terminator kinds or successors
             let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
-            let init_statement =
-                basic_blocks[init_loc.block].statements[init_loc.statement_index].replace_nop();
-            let StatementKind::Assign(place_and_rvalue) = init_statement.kind else {
+            let init_statement_kind = std::mem::replace(
+                &mut basic_blocks[init_loc.block].statements[init_loc.statement_index].kind,
+                StatementKind::Nop,
+            );
+            let StatementKind::Assign(place_and_rvalue) = init_statement_kind else {
                 bug!("No longer an assign?");
             };
             let (place, rvalue) = *place_and_rvalue;
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index e4a733fcbce..1195c25e130 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -478,7 +478,7 @@ fn collect_items_rec<'tcx>(
             );
             recursion_depth_reset = None;
 
-            let item = tcx.hir().item(item_id);
+            let item = tcx.hir_item(item_id);
             if let hir::ItemKind::GlobalAsm(asm) = item.kind {
                 for (op, op_sp) in asm.operands {
                     match op {
diff --git a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs
index d8c1dc8b4e9..0fc313e33b3 100644
--- a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs
@@ -34,7 +34,17 @@ where
     ) -> QueryResult<I> {
         let cx = self.cx();
         let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
-        debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some());
+
+        // Check that the alias-relate goal is reasonable. Writeback for
+        // `coroutine_stalled_predicates` can replace alias terms with
+        // `{type error}` if the alias still contains infer vars, so we also
+        // accept alias-relate goals where one of the terms is an error.
+        debug_assert!(
+            lhs.to_alias_term().is_some()
+                || rhs.to_alias_term().is_some()
+                || lhs.is_error()
+                || rhs.is_error()
+        );
 
         // Structurally normalize the lhs.
         let lhs = if let Some(alias) = lhs.to_alias_term() {
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 b0f59ed1474..bfb590e8767 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -791,7 +791,7 @@ where
             return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Ambiguity));
         };
 
-        let responses: Vec<_> = match proven_via {
+        match proven_via {
             // Even when a trait bound has been proven using a where-bound, we
             // still need to consider alias-bounds for normalization, see
             // tests/ui/next-solver/alias-bound-shadowed-by-env.rs.
@@ -800,7 +800,7 @@ where
             // constness checking. Doing so is *at least theoretically* breaking,
             // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754
             TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
-                let mut candidates_from_env: Vec<_> = candidates
+                let mut candidates_from_env_and_bounds: Vec<_> = candidates
                     .iter()
                     .filter(|c| {
                         matches!(
@@ -813,16 +813,37 @@ where
 
                 // If the trait goal has been proven by using the environment, we want to treat
                 // aliases as rigid if there are no applicable projection bounds in the environment.
-                if candidates_from_env.is_empty() {
+                if candidates_from_env_and_bounds.is_empty() {
                     if let Ok(response) = inject_normalize_to_rigid_candidate(self) {
-                        candidates_from_env.push(response);
+                        candidates_from_env_and_bounds.push(response);
                     }
                 }
-                candidates_from_env
+
+                if let Some(response) = self.try_merge_responses(&candidates_from_env_and_bounds) {
+                    Ok(response)
+                } else {
+                    self.flounder(&candidates_from_env_and_bounds)
+                }
             }
-            TraitGoalProvenVia::Misc => candidates.iter().map(|c| c.result).collect(),
-        };
+            TraitGoalProvenVia::Misc => {
+                // Prefer "orphaned" param-env normalization predicates, which are used
+                // (for example, and ideally only) when proving item bounds for an impl.
+                let candidates_from_env: Vec<_> = candidates
+                    .iter()
+                    .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
+                    .map(|c| c.result)
+                    .collect();
+                if let Some(response) = self.try_merge_responses(&candidates_from_env) {
+                    return Ok(response);
+                }
 
-        self.try_merge_responses(&responses).map_or_else(|| self.flounder(&responses), Ok)
+                let responses: Vec<_> = candidates.iter().map(|c| c.result).collect();
+                if let Some(response) = self.try_merge_responses(&responses) {
+                    Ok(response)
+                } else {
+                    self.flounder(&responses)
+                }
+            }
+        }
     }
 }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index ea464fc8ebb..bbd73dec2e4 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -117,12 +117,15 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
     ($self: expr, $allow_qpath_recovery: expr) => {
         if $allow_qpath_recovery
             && $self.may_recover()
-            && $self.look_ahead(1, |t| t == &token::PathSep)
-            && let token::Interpolated(nt) = &$self.token.kind
-            && let token::NtTy(ty) = &**nt
+            && let Some(mv_kind) = $self.token.is_metavar_seq()
+            && let token::MetaVarKind::Ty { .. } = mv_kind
+            && $self.check_noexpect_past_close_delim(&token::PathSep)
         {
-            let ty = ty.clone();
-            $self.bump();
+            // Reparse the type, then move to recovery.
+            let ty = $self
+                .eat_metavar_seq(mv_kind, |this| this.parse_ty_no_question_mark_recover())
+                .expect("metavar seq ty");
+
             return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_token.span, ty);
         }
     };
@@ -614,6 +617,24 @@ impl<'a> Parser<'a> {
         self.token == *tok
     }
 
+    // Check the first token after the delimiter that closes the current
+    // delimited sequence. (Panics if used in the outermost token stream, which
+    // has no delimiters.) It uses a clone of the relevant tree cursor to skip
+    // past the entire `TokenTree::Delimited` in a single step, avoiding the
+    // need for unbounded token lookahead.
+    //
+    // Primarily used when `self.token` matches
+    // `OpenDelim(Delimiter::Invisible(_))`, to look ahead through the current
+    // metavar expansion.
+    fn check_noexpect_past_close_delim(&self, tok: &TokenKind) -> bool {
+        let mut tree_cursor = self.token_cursor.stack.last().unwrap().clone();
+        tree_cursor.bump();
+        matches!(
+            tree_cursor.curr(),
+            Some(TokenTree::Token(token::Token { kind, .. }, _)) if kind == tok
+        )
+    }
+
     /// Consumes a token 'tok' if it exists. Returns whether the given token was present.
     ///
     /// the main purpose of this function is to reduce the cluttering of the suggestions list
@@ -721,6 +742,43 @@ impl<'a> Parser<'a> {
         if !self.eat_keyword(exp) { self.unexpected() } else { Ok(()) }
     }
 
+    /// Consume a sequence produced by a metavar expansion, if present.
+    fn eat_metavar_seq<T>(
+        &mut self,
+        mv_kind: MetaVarKind,
+        f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+    ) -> Option<T> {
+        self.eat_metavar_seq_with_matcher(|mvk| mvk == mv_kind, f)
+    }
+
+    /// A slightly more general form of `eat_metavar_seq`, for use with the
+    /// `MetaVarKind` variants that have parameters, where an exact match isn't
+    /// desired.
+    fn eat_metavar_seq_with_matcher<T>(
+        &mut self,
+        match_mv_kind: impl Fn(MetaVarKind) -> bool,
+        mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+    ) -> Option<T> {
+        if let token::OpenDelim(delim) = self.token.kind
+            && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim
+            && match_mv_kind(mv_kind)
+        {
+            self.bump();
+            let res = f(self).expect("failed to reparse {mv_kind:?}");
+            if let token::CloseDelim(delim) = self.token.kind
+                && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim
+                && match_mv_kind(mv_kind)
+            {
+                self.bump();
+                Some(res)
+            } else {
+                panic!("no close delim when reparsing {mv_kind:?}");
+            }
+        } else {
+            None
+        }
+    }
+
     /// Is the given keyword `kw` followed by a non-reserved identifier?
     fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
         self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
@@ -754,9 +812,9 @@ impl<'a> Parser<'a> {
         self.is_keyword_ahead(0, &[kw::Const])
             && self.look_ahead(1, |t| match &t.kind {
                 // async closures do not work with const closures, so we do not parse that here.
-                token::Ident(kw::Move | kw::Static, _) | token::OrOr | token::BinOp(token::Or) => {
-                    true
-                }
+                token::Ident(kw::Move | kw::Static, IdentIsRaw::No)
+                | token::OrOr
+                | token::BinOp(token::Or) => true,
                 _ => false,
             })
     }
@@ -1455,7 +1513,11 @@ impl<'a> Parser<'a> {
     /// so emit a proper diagnostic.
     // Public for rustfmt usage.
     pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
-        maybe_whole!(self, NtVis, |vis| vis.into_inner());
+        if let Some(vis) = self
+            .eat_metavar_seq(MetaVarKind::Vis, |this| this.parse_visibility(FollowedByType::Yes))
+        {
+            return Ok(vis);
+        }
 
         if !self.eat_keyword(exp!(Pub)) {
             // We need a span for our `Spanned<VisibilityKind>`, but there's inherently no
@@ -1683,7 +1745,9 @@ pub enum ParseNtResult {
     Tt(TokenTree),
     Ident(Ident, IdentIsRaw),
     Lifetime(Ident, IdentIsRaw),
+    Ty(P<ast::Ty>),
+    Vis(P<ast::Visibility>),
 
-    /// This case will eventually be removed, along with `Token::Interpolate`.
+    /// This variant will eventually be removed, along with `Token::Interpolate`.
     Nt(Arc<Nonterminal>),
 }
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index eefdb641da2..f202f85752e 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -30,7 +30,7 @@ impl<'a> Parser<'a> {
                 MetaVarKind::Stmt
                 | MetaVarKind::Pat(_)
                 | MetaVarKind::Expr { .. }
-                | MetaVarKind::Ty
+                | MetaVarKind::Ty { .. }
                 | MetaVarKind::Literal // `true`, `false`
                 | MetaVarKind::Meta
                 | MetaVarKind::Path => true,
@@ -51,14 +51,11 @@ impl<'a> Parser<'a> {
                 NtStmt(_)
                 | NtPat(_)
                 | NtExpr(_)
-                | NtTy(_)
                 | NtLiteral(_) // `true`, `false`
                 | NtMeta(_)
                 | NtPath(_) => true,
 
-                NtItem(_)
-                | NtBlock(_)
-                | NtVis(_) => false,
+                NtItem(_) | NtBlock(_) => false,
             }
         }
 
@@ -88,7 +85,7 @@ impl<'a> Parser<'a> {
             NonterminalKind::Ident => get_macro_ident(token).is_some(),
             NonterminalKind::Literal => token.can_begin_literal_maybe_minus(),
             NonterminalKind::Vis => match token.kind {
-                // The follow-set of :vis + "priv" keyword + interpolated
+                // The follow-set of :vis + "priv" keyword + interpolated/metavar-expansion.
                 token::Comma
                 | token::Ident(..)
                 | token::NtIdent(..)
@@ -102,7 +99,7 @@ impl<'a> Parser<'a> {
                 token::NtLifetime(..) => true,
                 token::Interpolated(nt) => match &**nt {
                     NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
-                    NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) | NtVis(_) => false,
+                    NtItem(_) | NtPat(_) | NtMeta(_) | NtPath(_) => false,
                 },
                 token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
                     MetaVarKind::Block
@@ -111,7 +108,7 @@ impl<'a> Parser<'a> {
                     | MetaVarKind::Literal => true,
                     MetaVarKind::Item
                     | MetaVarKind::Pat(_)
-                    | MetaVarKind::Ty
+                    | MetaVarKind::Ty { .. }
                     | MetaVarKind::Meta
                     | MetaVarKind::Path
                     | MetaVarKind::Vis => false,
@@ -189,7 +186,9 @@ impl<'a> Parser<'a> {
                 NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)
             }
             NonterminalKind::Ty => {
-                NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?)
+                return Ok(ParseNtResult::Ty(
+                    self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?,
+                ));
             }
             // this could be handled like a token, since it is one
             NonterminalKind::Ident => {
@@ -208,8 +207,9 @@ impl<'a> Parser<'a> {
             }
             NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(ForceCollect::Yes)?)),
             NonterminalKind::Vis => {
-                NtVis(P(self
-                    .collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))
+                return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| {
+                    this.parse_visibility(FollowedByType::Yes)
+                })?)));
             }
             NonterminalKind::Lifetime => {
                 // We want to keep `'keyword` parsing, just like `keyword` is still
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index b241aa892db..c24305ea9a8 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -2,7 +2,7 @@ use std::mem;
 
 use ast::token::IdentIsRaw;
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, MetaVarKind, Token, TokenKind};
 use rustc_ast::{
     self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint,
     AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
@@ -196,14 +196,12 @@ impl<'a> Parser<'a> {
 
         maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner()));
 
-        if let token::Interpolated(nt) = &self.token.kind {
-            if let token::NtTy(ty) = &**nt {
-                if let ast::TyKind::Path(None, path) = &ty.kind {
-                    let path = path.clone();
-                    self.bump();
-                    return Ok(reject_generics_if_mod_style(self, path));
-                }
-            }
+        // If we have a `ty` metavar in the form of a path, reparse it directly as a path, instead
+        // of reparsing it as a `ty` and then extracting the path.
+        if let Some(path) = self.eat_metavar_seq(MetaVarKind::Ty { is_path: true }, |this| {
+            this.parse_path(PathStyle::Type)
+        }) {
+            return Ok(reject_generics_if_mod_style(self, path));
         }
 
         let lo = self.token.span;
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index dc5919b3630..18af0a1c79a 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -1,5 +1,5 @@
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token, TokenKind};
+use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, MetaVarKind, Token, TokenKind};
 use rustc_ast::util::case::Case;
 use rustc_ast::{
     self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
@@ -18,7 +18,7 @@ use crate::errors::{
     HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
     NestedCVariadicType, ReturnTypesUseThinArrow,
 };
-use crate::{exp, maybe_recover_from_interpolated_ty_qpath, maybe_whole};
+use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
 
 /// Signals whether parsing a type should allow `+`.
 ///
@@ -183,7 +183,8 @@ impl<'a> Parser<'a> {
         )
     }
 
-    /// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>`
+    /// Parse a type without recovering `:` as `->` to avoid breaking code such
+    /// as `where fn() : for<'a>`.
     pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
         self.parse_ty_common(
             AllowPlus::Yes,
@@ -247,7 +248,13 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, P<Ty>> {
         let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
         maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
-        maybe_whole!(self, NtTy, |ty| ty);
+
+        if let Some(ty) = self.eat_metavar_seq_with_matcher(
+            |mv_kind| matches!(mv_kind, MetaVarKind::Ty { .. }),
+            |this| this.parse_ty_no_question_mark_recover(),
+        ) {
+            return Ok(ty);
+        }
 
         let lo = self.token.span;
         let mut impl_dyn_multi = false;
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index f578708b40c..5111a025f94 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -627,7 +627,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     fn check_object_lifetime_default(&self, hir_id: HirId) {
         let tcx = self.tcx;
         if let Some(owner_id) = hir_id.as_owner()
-            && let Some(generics) = tcx.hir().get_generics(owner_id.def_id)
+            && let Some(generics) = tcx.hir_get_generics(owner_id.def_id)
         {
             for p in generics.params {
                 let hir::GenericParamKind::Type { .. } = p.kind else { continue };
@@ -2461,7 +2461,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         if let Err(terr) = ocx.eq(&cause, param_env, expected_sig, sig) {
             let mut diag = tcx.dcx().create_err(errors::ProcMacroBadSig { span, kind });
 
-            let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id);
+            let hir_sig = tcx.hir_fn_sig_by_hir_id(hir_id);
             if let Some(hir_sig) = hir_sig {
                 #[allow(rustc::diagnostic_outside_of_impl)] // FIXME
                 match terr {
@@ -2606,8 +2606,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
 impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
@@ -2740,9 +2740,8 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
             for attr_to_check in ATTRS_TO_CHECK {
                 if attr.has_name(*attr_to_check) {
                     let item = tcx
-                        .hir()
-                        .items()
-                        .map(|id| tcx.hir().item(id))
+                        .hir_free_items()
+                        .map(|id| tcx.hir_item(id))
                         .find(|item| !item.span.is_dummy()) // Skip prelude `use`s
                         .map(|item| errors::ItemFollowingInnerAttr {
                             span: item.ident.span,
@@ -2792,10 +2791,10 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
 
 fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
     let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) };
-    tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor);
+    tcx.hir_visit_item_likes_in_module(module_def_id, check_attr_visitor);
     if module_def_id.to_local_def_id().is_top_level_module() {
         check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
-        check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
+        check_invalid_crate_level_attr(tcx, tcx.hir_krate_attrs());
     }
     if check_attr_visitor.abort.get() {
         tcx.dcx().abort_if_errors()
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 95f18eaa7ef..7b4fecf2ed1 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -358,7 +358,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
             if let Some(local_impl_of) = impl_of.as_local()
                 && let Some(local_def_id) = def_id.as_local()
                 && let Some(fn_sig) =
-                    self.tcx.hir().fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
+                    self.tcx.hir_fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
                 && matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None)
                 && let TyKind::Path(hir::QPath::Resolved(_, path)) =
                     self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind
@@ -531,7 +531,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
 
     fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId, impl_item_id: LocalDefId) -> bool {
         if let TyKind::Path(hir::QPath::Resolved(_, path)) =
-            self.tcx.hir().item(impl_id).expect_impl().self_ty.kind
+            self.tcx.hir_item(impl_id).expect_impl().self_ty.kind
             && let Res::Def(def_kind, def_id) = path.res
             && let Some(local_def_id) = def_id.as_local()
             && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
@@ -559,7 +559,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
     fn visit_nested_body(&mut self, body: hir::BodyId) {
         let old_maybe_typeck_results =
             self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
-        let body = self.tcx.hir().body(body);
+        let body = self.tcx.hir_body(body);
         self.visit_body(body);
         self.maybe_typeck_results = old_maybe_typeck_results;
     }
@@ -750,7 +750,7 @@ fn check_item<'tcx>(
 
     match tcx.def_kind(id.owner_id) {
         DefKind::Enum => {
-            let item = tcx.hir().item(id);
+            let item = tcx.hir_item(id);
             if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
                 if let Some(comes_from_allow) = allow_dead_code {
                     worklist.extend(
@@ -772,14 +772,14 @@ fn check_item<'tcx>(
                 .iter()
                 .filter_map(|def_id| def_id.as_local());
 
-            let ty_is_pub = ty_ref_to_pub_struct(tcx, tcx.hir().item(id).expect_impl().self_ty);
+            let ty_is_pub = ty_ref_to_pub_struct(tcx, tcx.hir_item(id).expect_impl().self_ty);
 
             // And we access the Map here to get HirId from LocalDefId
             for local_def_id in local_def_ids {
                 // check the function may construct Self
                 let mut may_construct_self = false;
                 if let Some(fn_sig) =
-                    tcx.hir().fn_sig_by_hir_id(tcx.local_def_id_to_hir_id(local_def_id))
+                    tcx.hir_fn_sig_by_hir_id(tcx.local_def_id_to_hir_id(local_def_id))
                 {
                     may_construct_self =
                         matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None);
@@ -805,7 +805,7 @@ fn check_item<'tcx>(
             }
         }
         DefKind::Struct => {
-            let item = tcx.hir().item(id);
+            let item = tcx.hir_item(id);
             if let hir::ItemKind::Struct(ref variant_data, _) = item.kind
                 && let Some(ctor_def_id) = variant_data.ctor_def_id()
             {
@@ -827,7 +827,7 @@ fn check_trait_item(
 ) {
     use hir::TraitItemKind::{Const, Fn};
     if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) {
-        let trait_item = tcx.hir().trait_item(id);
+        let trait_item = tcx.hir_trait_item(id);
         if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..))
             && let Some(comes_from_allow) =
                 has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id)
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 22291c9282d..c2225ea1e64 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -37,7 +37,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
 
     let mut ctxt = EntryContext { tcx, rustc_main_fn: None, non_main_fns: Vec::new() };
 
-    for id in tcx.hir().items() {
+    for id in tcx.hir_free_items() {
         check_and_search_item(id, &mut ctxt);
     }
 
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 74038b24dcc..509c2f54775 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -9,11 +9,11 @@ use rustc_middle::ty::TyCtxt;
 pub fn check_crate(tcx: TyCtxt<'_>) {
     let errors = Lock::new(Vec::new());
 
-    tcx.hir().par_for_each_module(|module_id| {
+    tcx.par_hir_for_each_module(|module_id| {
         let mut v =
             HirIdValidator { tcx, owner: None, hir_ids_seen: Default::default(), errors: &errors };
 
-        tcx.hir().visit_item_likes_in_module(module_id, &mut v);
+        tcx.hir_visit_item_likes_in_module(module_id, &mut v);
     });
 
     let errors = errors.into_inner();
@@ -61,7 +61,7 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
 
         if max != self.hir_ids_seen.len() - 1 {
             let hir = self.tcx.hir();
-            let pretty_owner = hir.def_path(owner.def_id).to_string_no_crate_verbose();
+            let pretty_owner = self.tcx.hir_def_path(owner.def_id).to_string_no_crate_verbose();
 
             let missing_items: Vec<_> = (0..=max as u32)
                 .map(|i| ItemLocalId::from_u32(i))
@@ -105,8 +105,8 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
 impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_nested_item(&mut self, id: hir::ItemId) {
@@ -138,8 +138,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
                 format!(
                     "HirIdValidator: The recorded owner of {} is {} instead of {}",
                     self.tcx.hir().node_to_string(hir_id),
-                    self.tcx.hir().def_path(hir_id.owner.def_id).to_string_no_crate_verbose(),
-                    self.tcx.hir().def_path(owner.def_id).to_string_no_crate_verbose()
+                    self.tcx.hir_def_path(hir_id.owner.def_id).to_string_no_crate_verbose(),
+                    self.tcx.hir_def_path(owner.def_id).to_string_no_crate_verbose()
                 )
             });
         }
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index f7cae89852e..92ea49f18e5 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -7,7 +7,6 @@ use rustc_ast::{self as ast, NodeId, visit as ast_visit};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::thousands::format_with_underscores;
 use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
-use rustc_middle::hir::map::Map;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
@@ -56,19 +55,16 @@ impl Node {
 /// a `visit_*` method for, and so we cannot measure these, which is
 /// unfortunate.
 struct StatCollector<'k> {
-    krate: Option<Map<'k>>,
+    tcx: Option<TyCtxt<'k>>,
     nodes: FxHashMap<&'static str, Node>,
     seen: FxHashSet<HirId>,
 }
 
 pub fn print_hir_stats(tcx: TyCtxt<'_>) {
-    let mut collector = StatCollector {
-        krate: Some(tcx.hir()),
-        nodes: FxHashMap::default(),
-        seen: FxHashSet::default(),
-    };
-    tcx.hir().walk_toplevel_module(&mut collector);
-    tcx.hir().walk_attributes(&mut collector);
+    let mut collector =
+        StatCollector { tcx: Some(tcx), nodes: FxHashMap::default(), seen: FxHashSet::default() };
+    tcx.hir_walk_toplevel_module(&mut collector);
+    tcx.hir_walk_attributes(&mut collector);
     collector.print("HIR STATS", "hir-stats");
 }
 
@@ -76,7 +72,7 @@ pub fn print_ast_stats(krate: &ast::Crate, title: &str, prefix: &str) {
     use rustc_ast::visit::Visitor;
 
     let mut collector =
-        StatCollector { krate: None, nodes: FxHashMap::default(), seen: FxHashSet::default() };
+        StatCollector { tcx: None, nodes: FxHashMap::default(), seen: FxHashSet::default() };
     collector.visit_crate(krate);
     collector.print(title, prefix);
 }
@@ -205,27 +201,27 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
     }
 
     fn visit_nested_item(&mut self, id: hir::ItemId) {
-        let nested_item = self.krate.unwrap().item(id);
+        let nested_item = self.tcx.unwrap().hir_item(id);
         self.visit_item(nested_item)
     }
 
     fn visit_nested_trait_item(&mut self, trait_item_id: hir::TraitItemId) {
-        let nested_trait_item = self.krate.unwrap().trait_item(trait_item_id);
+        let nested_trait_item = self.tcx.unwrap().hir_trait_item(trait_item_id);
         self.visit_trait_item(nested_trait_item)
     }
 
     fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) {
-        let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id);
+        let nested_impl_item = self.tcx.unwrap().hir_impl_item(impl_item_id);
         self.visit_impl_item(nested_impl_item)
     }
 
     fn visit_nested_foreign_item(&mut self, id: hir::ForeignItemId) {
-        let nested_foreign_item = self.krate.unwrap().foreign_item(id);
+        let nested_foreign_item = self.tcx.unwrap().hir_foreign_item(id);
         self.visit_foreign_item(nested_foreign_item);
     }
 
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
-        let nested_body = self.krate.unwrap().body(body_id);
+        let nested_body = self.tcx.unwrap().hir_body(body_id);
         self.visit_body(nested_body)
     }
 
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 600c46eb3d0..e123fbac1be 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -129,8 +129,8 @@ impl<'tcx> LibFeatureCollector<'tcx> {
 impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_attribute(&mut self, attr: &'tcx Attribute) {
@@ -148,7 +148,7 @@ fn lib_features(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> LibFeatures {
     }
 
     let mut collector = LibFeatureCollector::new(tcx);
-    tcx.hir().walk_attributes(&mut collector);
+    tcx.hir_walk_attributes(&mut collector);
     collector.lib_features
 }
 
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 60f7616a5fb..a7bca67e4e4 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -152,8 +152,8 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     }
 
     let mut maps = IrMaps::new(tcx);
-    let body = tcx.hir().body_owned_by(def_id);
-    let hir_id = tcx.hir().body_owner(body.id());
+    let body = tcx.hir_body_owned_by(def_id);
+    let hir_id = tcx.hir_body_owner(body.id());
 
     if let Some(upvars) = tcx.upvars_mentioned(def_id) {
         for &var_hir_id in upvars.keys() {
@@ -1522,8 +1522,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
     }
 
     fn warn_about_unused_args(&self, body: &hir::Body<'_>, entry_ln: LiveNode) {
-        if let Some(intrinsic) =
-            self.ir.tcx.intrinsic(self.ir.tcx.hir().body_owner_def_id(body.id()))
+        if let Some(intrinsic) = self.ir.tcx.intrinsic(self.ir.tcx.hir_body_owner_def_id(body.id()))
         {
             if intrinsic.must_be_overridden {
                 return;
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 6eef0b926a1..8e59c0b3251 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -76,7 +76,7 @@ struct CheckLoopVisitor<'tcx> {
 fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
     let mut check =
         CheckLoopVisitor { tcx, cx_stack: vec![Normal], block_breaks: Default::default() };
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut check);
+    tcx.hir_visit_item_likes_in_module(module_def_id, &mut check);
     check.report_outside_loop_error();
 }
 
@@ -87,8 +87,8 @@ pub(crate) fn provide(providers: &mut Providers) {
 impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) {
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 875b6edb58c..cb17b0f6cf5 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -45,7 +45,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
             _ => continue,
         };
 
-        let body = tcx.hir().body(body_id);
+        let body = tcx.hir_body(body_id);
 
         if tcx.has_attr(def_id, sym::naked) {
             check_abi(tcx, def_id, fn_header.abi);
@@ -259,8 +259,8 @@ struct CheckNakedAsmInNakedFn<'tcx> {
 impl<'tcx> Visitor<'tcx> for CheckNakedAsmInNakedFn<'tcx> {
     type NestedFilter = OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 7788adb6e17..1fe44bd3d21 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -66,7 +66,7 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
     fn visit_nested_body(&mut self, body: hir::BodyId) {
         let old_maybe_typeck_results =
             self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
-        let body = self.tcx.hir().body(body);
+        let body = self.tcx.hir_body(body);
         self.visit_body(body);
         self.maybe_typeck_results = old_maybe_typeck_results;
     }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index fd30d0d4867..a6585946656 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -394,8 +394,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     /// deep-walking.
     type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
@@ -616,8 +616,8 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
 impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
@@ -721,7 +721,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
             InheritDeprecation::Yes,
             InheritConstStability::No,
             InheritStability::No,
-            |v| tcx.hir().walk_toplevel_module(v),
+            |v| tcx.hir_walk_toplevel_module(v),
         );
     }
     index
@@ -730,7 +730,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
 /// Cross-references the feature names of unstable APIs with enabled
 /// features and possibly prints errors.
 fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
+    tcx.hir_visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
@@ -756,8 +756,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
     /// Because stability levels are scoped lexically, we want to walk
     /// nested items in the context of the outer item, so enable
     /// deep-walking.
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -1059,8 +1059,8 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
         let effective_visibilities = &tcx.effective_visibilities(());
         let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
         missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
-        tcx.hir().walk_toplevel_module(&mut missing);
-        tcx.hir().visit_all_item_likes_in_crate(&mut missing);
+        tcx.hir_walk_toplevel_module(&mut missing);
+        tcx.hir_visit_all_item_likes_in_crate(&mut missing);
     }
 
     let enabled_lang_features = tcx.features().enabled_lang_features();
diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs
index 0544d08f5b1..fae88fbba36 100644
--- a/compiler/rustc_passes/src/upvars.rs
+++ b/compiler/rustc_passes/src/upvars.rs
@@ -16,7 +16,7 @@ pub(crate) fn provide(providers: &mut Providers) {
         }
 
         let local_def_id = def_id.expect_local();
-        let body = tcx.hir().maybe_body_owned_by(local_def_id)?;
+        let body = tcx.hir_maybe_body_owned_by(local_def_id)?;
 
         let mut local_collector = LocalCollector::default();
         local_collector.visit_body(&body);
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 2694cf472f4..0b1e954d64d 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -1084,12 +1084,16 @@ pub fn analyze_match<'p, 'tcx>(
     tycx: &RustcPatCtxt<'p, 'tcx>,
     arms: &[MatchArm<'p, 'tcx>],
     scrut_ty: Ty<'tcx>,
-    pattern_complexity_limit: Option<usize>,
 ) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
     let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
     let scrut_validity = PlaceValidity::from_bool(tycx.known_valid_scrutinee);
-    let report =
-        compute_match_usefulness(tycx, arms, scrut_ty, scrut_validity, pattern_complexity_limit)?;
+    let report = compute_match_usefulness(
+        tycx,
+        arms,
+        scrut_ty,
+        scrut_validity,
+        tycx.tcx.pattern_complexity_limit().0,
+    )?;
 
     // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
     // `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index cc09cd491af..1dff76141da 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -795,20 +795,21 @@ struct UsefulnessCtxt<'a, 'p, Cx: PatCx> {
     /// Track information about the usefulness of branch patterns (see definition of "branch
     /// pattern" at [`BranchPatUsefulness`]).
     branch_usefulness: FxHashMap<PatId, BranchPatUsefulness<'p, Cx>>,
-    complexity_limit: Option<usize>,
+    // Ideally this field would have type `Limit`, but this crate is used by
+    // rust-analyzer which cannot have a dependency on `Limit`, because `Limit`
+    // is from crate `rustc_session` which uses unstable Rust features.
+    complexity_limit: usize,
     complexity_level: usize,
 }
 
 impl<'a, 'p, Cx: PatCx> UsefulnessCtxt<'a, 'p, Cx> {
     fn increase_complexity_level(&mut self, complexity_add: usize) -> Result<(), Cx::Error> {
         self.complexity_level += complexity_add;
-        if self
-            .complexity_limit
-            .is_some_and(|complexity_limit| complexity_limit < self.complexity_level)
-        {
-            return self.tycx.complexity_exceeded();
+        if self.complexity_level <= self.complexity_limit {
+            Ok(())
+        } else {
+            self.tycx.complexity_exceeded()
         }
-        Ok(())
     }
 }
 
@@ -1834,7 +1835,7 @@ pub fn compute_match_usefulness<'p, Cx: PatCx>(
     arms: &[MatchArm<'p, Cx>],
     scrut_ty: Cx::Ty,
     scrut_validity: PlaceValidity,
-    complexity_limit: Option<usize>,
+    complexity_limit: usize,
 ) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> {
     let mut cx = UsefulnessCtxt {
         tycx,
diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs
index cd697632d1b..23560ad6419 100644
--- a/compiler/rustc_pattern_analysis/tests/common/mod.rs
+++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs
@@ -124,7 +124,7 @@ pub fn compute_match_usefulness<'p>(
     arms: &[MatchArm<'p, Cx>],
     ty: Ty,
     scrut_validity: PlaceValidity,
-    complexity_limit: Option<usize>,
+    complexity_limit: usize,
 ) -> Result<UsefulnessReport<'p, Cx>, ()> {
     init_tracing();
     rustc_pattern_analysis::usefulness::compute_match_usefulness(
diff --git a/compiler/rustc_pattern_analysis/tests/complexity.rs b/compiler/rustc_pattern_analysis/tests/complexity.rs
index 43b585bc533..abd1ec24d93 100644
--- a/compiler/rustc_pattern_analysis/tests/complexity.rs
+++ b/compiler/rustc_pattern_analysis/tests/complexity.rs
@@ -14,7 +14,7 @@ fn check(patterns: &[DeconstructedPat<Cx>], complexity_limit: usize) -> Result<(
     let ty = *patterns[0].ty();
     let arms: Vec<_> =
         patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
-    compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, Some(complexity_limit))
+    compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, complexity_limit)
         .map(|_report| ())
 }
 
diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
index 0d80042a850..61ce0fd11e7 100644
--- a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
+++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
@@ -14,7 +14,8 @@ fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> {
     let arms: Vec<_> =
         patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
     let report =
-        compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, None).unwrap();
+        compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, usize::MAX)
+            .unwrap();
     report.non_exhaustiveness_witnesses
 }
 
diff --git a/compiler/rustc_pattern_analysis/tests/intersection.rs b/compiler/rustc_pattern_analysis/tests/intersection.rs
index a852056b6a6..45674338efd 100644
--- a/compiler/rustc_pattern_analysis/tests/intersection.rs
+++ b/compiler/rustc_pattern_analysis/tests/intersection.rs
@@ -14,7 +14,8 @@ fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<Vec<usize>> {
     let arms: Vec<_> =
         patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
     let report =
-        compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, None).unwrap();
+        compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, usize::MAX)
+            .unwrap();
     report.arm_intersections.into_iter().map(|bitset| bitset.iter().collect()).collect()
 }
 
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 3842b7035e5..6faa2c1a00d 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1036,7 +1036,7 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
             return;
         }
         let old_maybe_typeck_results = self.maybe_typeck_results.replace(new_typeck_results);
-        self.visit_body(self.tcx.hir().body(body_id));
+        self.visit_body(self.tcx.hir_body(body_id));
         self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
@@ -1161,7 +1161,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
         let old_maybe_typeck_results =
             self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id));
-        self.visit_body(self.tcx.hir().body(body_id));
+        self.visit_body(self.tcx.hir_body(body_id));
         self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
@@ -1599,7 +1599,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
                 self.check(def_id, item_visibility, effective_vis).generics().bounds();
             }
             DefKind::Trait => {
-                let item = tcx.hir().item(id);
+                let item = tcx.hir_item(id);
                 if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind {
                     self.check_unnameable(item.owner_id.def_id, effective_vis);
 
@@ -1630,7 +1630,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
                 self.check(def_id, item_visibility, effective_vis).generics().predicates();
             }
             DefKind::Enum => {
-                let item = tcx.hir().item(id);
+                let item = tcx.hir_item(id);
                 if let hir::ItemKind::Enum(ref def, _) = item.kind {
                     self.check_unnameable(item.owner_id.def_id, effective_vis);
 
@@ -1647,10 +1647,10 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
             }
             // Subitems of foreign modules have their own publicity.
             DefKind::ForeignMod => {
-                let item = tcx.hir().item(id);
+                let item = tcx.hir_item(id);
                 if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
                     for foreign_item in items {
-                        let foreign_item = tcx.hir().foreign_item(foreign_item.id);
+                        let foreign_item = tcx.hir_foreign_item(foreign_item.id);
 
                         let ev = self.get(foreign_item.owner_id.def_id);
                         let vis = tcx.local_visibility(foreign_item.owner_id.def_id);
@@ -1668,7 +1668,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
             }
             // Subitems of structs and unions have their own publicity.
             DefKind::Struct | DefKind::Union => {
-                let item = tcx.hir().item(id);
+                let item = tcx.hir_item(id);
                 if let hir::ItemKind::Struct(ref struct_def, _)
                 | hir::ItemKind::Union(ref struct_def, _) = item.kind
                 {
@@ -1695,7 +1695,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
             // A trait impl is public when both its type and its trait are public
             // Subitems of trait impls have inherited publicity.
             DefKind::Impl { .. } => {
-                let item = tcx.hir().item(id);
+                let item = tcx.hir_item(id);
                 if let hir::ItemKind::Impl(impl_) = item.kind {
                     let impl_vis = ty::Visibility::of_impl::<false>(
                         item.owner_id.def_id,
@@ -1771,7 +1771,7 @@ pub fn provide(providers: &mut Providers) {
 fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
     // Check privacy of names not checked in previous compilation stages.
     let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None };
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut visitor);
+    tcx.hir_visit_item_likes_in_module(module_def_id, &mut visitor);
 
     // Check privacy of explicitly written types and traits as well as
     // inferred types of expressions and patterns.
@@ -1782,13 +1782,13 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
     for def_id in module.definitions() {
         rustc_ty_utils::sig_types::walk_types(tcx, def_id, &mut visitor);
 
-        if let Some(body_id) = tcx.hir().maybe_body_owned_by(def_id) {
+        if let Some(body_id) = tcx.hir_maybe_body_owned_by(def_id) {
             visitor.visit_nested_body(body_id.id());
         }
     }
 
     for id in module.free_items() {
-        if let ItemKind::Impl(i) = tcx.hir().item(id).kind {
+        if let ItemKind::Impl(i) = tcx.hir_item(id).kind {
             if let Some(item) = i.of_trait {
                 let trait_ref = tcx.impl_trait_ref(id.owner_id.def_id).unwrap();
                 let trait_ref = trait_ref.instantiate_identity();
@@ -1863,7 +1863,7 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
     }
 
     loop {
-        tcx.hir().visit_all_item_likes_in_crate(&mut visitor);
+        tcx.hir_visit_all_item_likes_in_crate(&mut visitor);
         if visitor.changed {
             visitor.changed = false;
         } else {
@@ -1875,7 +1875,7 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
     let mut check_visitor =
         TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };
     check_visitor.effective_visibility_diagnostic(CRATE_DEF_ID);
-    tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor);
+    tcx.hir_visit_all_item_likes_in_crate(&mut check_visitor);
 
     tcx.arena.alloc(visitor.effective_visibilities)
 }
@@ -1885,7 +1885,7 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
     // Check for private types in public interfaces.
     let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities };
 
-    for id in tcx.hir().items() {
+    for id in tcx.hir_free_items() {
         checker.check_item(id);
     }
 }
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index 8b0cc9d726b..fd1d21b6a89 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2021"
 measureme = "11"
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index e95c186f6b6..f98d6421307 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -4,10 +4,11 @@
 
 use std::num::NonZero;
 
-use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::DiagInner;
+use rustc_hashes::Hash64;
 use rustc_index::Idx;
 use rustc_middle::bug;
 use rustc_middle::dep_graph::{
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index a42329b4614..d9560f3eb0f 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -13,6 +13,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index 82c51193a19..7490a3f3503 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -11,9 +11,9 @@ mod caches;
 pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache};
 
 mod config;
-use rustc_data_structures::stable_hasher::Hash64;
 use rustc_data_structures::sync::Lock;
 use rustc_errors::DiagInner;
+use rustc_hashes::Hash64;
 use rustc_hir::def::DefKind;
 use rustc_macros::{Decodable, Encodable};
 use rustc_span::Span;
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index b1b234eb757..46e52e1f131 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -182,6 +182,19 @@ pub(crate) struct ImportData<'ra> {
 /// so we can use referential equality to compare them.
 pub(crate) type Import<'ra> = Interned<'ra, ImportData<'ra>>;
 
+// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the
+// contained data.
+// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees
+// are upheld.
+impl std::hash::Hash for ImportData<'_> {
+    fn hash<H>(&self, _: &mut H)
+    where
+        H: std::hash::Hasher,
+    {
+        unreachable!()
+    }
+}
+
 impl<'ra> ImportData<'ra> {
     pub(crate) fn is_glob(&self) -> bool {
         matches!(self.kind, ImportKind::Glob { .. })
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 90191b7776f..5bc37e09f08 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -589,6 +589,19 @@ struct ModuleData<'ra> {
 #[rustc_pass_by_value]
 struct Module<'ra>(Interned<'ra, ModuleData<'ra>>);
 
+// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the
+// contained data.
+// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees
+// are upheld.
+impl std::hash::Hash for ModuleData<'_> {
+    fn hash<H>(&self, _: &mut H)
+    where
+        H: std::hash::Hasher,
+    {
+        unreachable!()
+    }
+}
+
 impl<'ra> ModuleData<'ra> {
     fn new(
         parent: Option<Module<'ra>>,
@@ -739,6 +752,19 @@ struct NameBindingData<'ra> {
 /// so we can use referential equality to compare them.
 type NameBinding<'ra> = Interned<'ra, NameBindingData<'ra>>;
 
+// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the
+// contained data.
+// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees
+// are upheld.
+impl std::hash::Hash for NameBindingData<'_> {
+    fn hash<H>(&self, _: &mut H)
+    where
+        H: std::hash::Hasher,
+    {
+        unreachable!()
+    }
+}
+
 trait ToNameBinding<'ra> {
     fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra>;
 }
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index 8bf98c16361..a6815c7a447 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 indexmap = "2.0.0"
+rustc_hashes = { path = "../rustc_hashes" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 thin-vec = "0.2.12"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index db8555edd0f..1eefd76f92b 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -10,6 +10,7 @@ use std::path;
 use std::rc::Rc;
 use std::sync::Arc;
 
+use rustc_hashes::{Hash64, Hash128};
 use smallvec::{Array, SmallVec};
 use thin_vec::ThinVec;
 
@@ -716,3 +717,31 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<[T]> {
         vec.into()
     }
 }
+
+impl<S: Encoder> Encodable<S> for Hash64 {
+    #[inline]
+    fn encode(&self, s: &mut S) {
+        s.emit_raw_bytes(&self.as_u64().to_le_bytes());
+    }
+}
+
+impl<S: Encoder> Encodable<S> for Hash128 {
+    #[inline]
+    fn encode(&self, s: &mut S) {
+        s.emit_raw_bytes(&self.as_u128().to_le_bytes());
+    }
+}
+
+impl<D: Decoder> Decodable<D> for Hash64 {
+    #[inline]
+    fn decode(d: &mut D) -> Self {
+        Self::new(u64::from_le_bytes(d.read_raw_bytes(8).try_into().unwrap()))
+    }
+}
+
+impl<D: Decoder> Decodable<D> for Hash128 {
+    #[inline]
+    fn decode(d: &mut D) -> Self {
+        Self::new(u128::from_le_bytes(d.read_raw_bytes(16).try_into().unwrap()))
+    }
+}
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index b9c535df4bd..31892c13438 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -14,6 +14,7 @@ rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
 rustc_fs_util = { path = "../rustc_fs_util" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_lint_defs = { path = "../rustc_lint_defs" }
 rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 7d473b86ff5..85ef69ea2b7 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -2934,9 +2934,9 @@ pub(crate) mod dep_tracking {
 
     use rustc_abi::Align;
     use rustc_data_structures::fx::FxIndexMap;
-    use rustc_data_structures::stable_hasher::Hash64;
     use rustc_errors::LanguageIdentifier;
     use rustc_feature::UnstableFeatures;
+    use rustc_hashes::Hash64;
     use rustc_span::RealFileName;
     use rustc_span::edition::Edition;
     use rustc_target::spec::{
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 35819f896c5..351dad3f3e4 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -7,9 +7,9 @@ use std::str;
 use rustc_abi::Align;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::profiling::TimePassesFormat;
-use rustc_data_structures::stable_hasher::Hash64;
 use rustc_errors::{ColorConfig, LanguageIdentifier, TerminalUrl};
 use rustc_feature::UnstableFeatures;
+use rustc_hashes::Hash64;
 use rustc_macros::{Decodable, Encodable};
 use rustc_span::edition::Edition;
 use rustc_span::{RealFileName, SourceFileHashAlgorithm};
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index f795ad1ee17..c4d45ee02ee 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -67,6 +67,11 @@ impl Limit {
         Limit(value)
     }
 
+    /// Create a new unlimited limit.
+    pub fn unlimited() -> Self {
+        Limit(usize::MAX)
+    }
+
     /// Check that `value` is within the limit. Ensures that the same comparisons are used
     /// throughout the compiler, as mismatches can cause ICEs, see #72540.
     #[inline]
@@ -119,6 +124,8 @@ pub struct Limits {
     pub move_size_limit: Limit,
     /// The maximum length of types during monomorphization.
     pub type_length_limit: Limit,
+    /// The maximum pattern complexity allowed (internal only).
+    pub pattern_complexity_limit: Limit,
 }
 
 pub struct CompilerIO {
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index 781fe6a11fe..991c75cc98d 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -12,6 +12,7 @@ itoa = "1.0"
 md5 = { package = "md-5", version = "0.10.0" }
 rustc_arena = { path = "../rustc_arena" }
 rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index f61ce37131e..641bac88ad0 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -3,10 +3,9 @@ use std::hash::{BuildHasherDefault, Hash, Hasher};
 
 use rustc_data_structures::AtomicRef;
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::stable_hasher::{
-    Hash64, HashStable, StableHasher, StableOrd, ToStableHashKey,
-};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
 use rustc_data_structures::unhash::Unhasher;
+use rustc_hashes::Hash64;
 use rustc_index::Idx;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_serialize::{Decodable, Encodable};
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 2910bcdf51d..9bf1d305e54 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -33,9 +33,10 @@ use std::sync::Arc;
 
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::stable_hasher::{Hash64, HashStable, HashingControls, StableHasher};
+use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher};
 use rustc_data_structures::sync::{Lock, WorkerLocal};
 use rustc_data_structures::unhash::UnhashMap;
+use rustc_hashes::Hash64;
 use rustc_index::IndexVec;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 0e146baef37..695edc956cd 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -87,9 +87,10 @@ use std::sync::Arc;
 use std::{fmt, iter};
 
 use md5::{Digest, Md5};
-use rustc_data_structures::stable_hasher::{Hash64, Hash128, HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock};
 use rustc_data_structures::unord::UnordMap;
+use rustc_hashes::{Hash64, Hash128};
 use sha1::Sha1;
 use sha2::Sha256;
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 62723e385cf..d155e95078b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -104,6 +104,8 @@ symbols! {
         Gen:                "gen", // >= 2024 Edition only
         Try:                "try", // >= 2018 Edition only
 
+        // NOTE: When adding new keywords, consider adding them to the ui/parser/raw/raw-idents.rs test.
+
         // "Lifetime keywords": regular keywords with a leading `'`.
         // Matching predicates: `is_any_keyword`
         UnderscoreLifetime: "'_",
@@ -190,6 +192,7 @@ symbols! {
         Capture,
         Cell,
         Center,
+        Child,
         Cleanup,
         Clone,
         CoercePointee,
@@ -334,6 +337,7 @@ symbols! {
         SliceIter,
         Some,
         SpanCtxt,
+        Stdin,
         String,
         StructuralPartialEq,
         SubdiagMessage,
@@ -597,6 +601,9 @@ symbols! {
         cfi,
         cfi_encoding,
         char,
+        char_is_ascii,
+        child_id,
+        child_kill,
         client,
         clippy,
         clobber_abi,
@@ -1466,6 +1473,7 @@ symbols! {
         panic_2015,
         panic_2021,
         panic_abort,
+        panic_any,
         panic_bounds_check,
         panic_cannot_unwind,
         panic_const_add_overflow,
@@ -1512,7 +1520,7 @@ symbols! {
         path_main_separator,
         path_to_pathbuf,
         pathbuf_as_path,
-        pattern_complexity,
+        pattern_complexity_limit,
         pattern_parentheses,
         pattern_type,
         pattern_types,
@@ -1571,6 +1579,7 @@ symbols! {
         proc_macro_mod,
         proc_macro_non_items,
         proc_macro_path_invoc,
+        process_abort,
         process_exit,
         profiler_builtins,
         profiler_runtime,
@@ -1973,6 +1982,10 @@ symbols! {
         str_from_utf8_mut,
         str_from_utf8_unchecked,
         str_from_utf8_unchecked_mut,
+        str_inherent_from_utf8,
+        str_inherent_from_utf8_mut,
+        str_inherent_from_utf8_unchecked,
+        str_inherent_from_utf8_unchecked_mut,
         str_len,
         str_split_whitespace,
         str_starts_with,
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index 1fb647cab5b..4c51c908f54 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -11,6 +11,7 @@ rustc-demangle = "0.1.21"
 rustc_abi = { path = "../rustc_abi" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_symbol_mangling/src/hashed.rs b/compiler/rustc_symbol_mangling/src/hashed.rs
index 07c5f544792..e965e6a7d53 100644
--- a/compiler/rustc_symbol_mangling/src/hashed.rs
+++ b/compiler/rustc_symbol_mangling/src/hashed.rs
@@ -1,6 +1,7 @@
 use std::fmt::Write;
 
-use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hashes::Hash64;
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::ty::{Instance, TyCtxt};
 
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 8ae35572d01..88754f1f15b 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -1,7 +1,8 @@
 use std::fmt::{self, Write};
 use std::mem::{self, discriminant};
 
-use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hashes::Hash64;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use rustc_middle::bug;
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 2bde1055622..c2a176facdf 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -7,7 +7,7 @@ use rustc_abi::{
 };
 use rustc_macros::HashStable_Generic;
 
-use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
+use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, RustcAbi, WasmCAbi};
 
 mod aarch64;
 mod amdgpu;
@@ -386,6 +386,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
     /// Pass this argument directly instead. Should NOT be used!
     /// Only exists because of past ABI mistakes that will take time to fix
     /// (see <https://github.com/rust-lang/rust/issues/115666>).
+    #[track_caller]
     pub fn make_direct_deprecated(&mut self) {
         match self.mode {
             PassMode::Indirect { .. } => {
@@ -398,6 +399,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
 
     /// Pass this argument indirectly, by passing a (thin or wide) pointer to the argument instead.
     /// This is valid for both sized and unsized arguments.
+    #[track_caller]
     pub fn make_indirect(&mut self) {
         match self.mode {
             PassMode::Direct(_) | PassMode::Pair(_, _) => {
@@ -412,6 +414,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
 
     /// Same as `make_indirect`, but for arguments that are ignored. Only needed for ABIs that pass
     /// ZSTs indirectly.
+    #[track_caller]
     pub fn make_indirect_from_ignore(&mut self) {
         match self.mode {
             PassMode::Ignore => {
@@ -716,7 +719,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
         C: HasDataLayout + HasTargetSpec,
     {
         let spec = cx.target_spec();
-        match &spec.arch[..] {
+        match &*spec.arch {
             "x86" => x86::compute_rust_abi_info(cx, self, abi),
             "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi),
             "loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi),
@@ -724,6 +727,22 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             _ => {}
         };
 
+        // Decides whether we can pass the given SIMD argument via `PassMode::Direct`.
+        // May only return `true` if the target will always pass those arguments the same way,
+        // no matter what the user does with `-Ctarget-feature`! In other words, whatever
+        // target features are required to pass a SIMD value in registers must be listed in
+        // the `abi_required_features` for the current target and ABI.
+        let can_pass_simd_directly = |arg: &ArgAbi<'_, Ty>| match &*spec.arch {
+            // On x86, if we have SSE2 (which we have by default for x86_64), we can always pass up
+            // to 128-bit-sized vectors.
+            "x86" if spec.rustc_abi == Some(RustcAbi::X86Sse2) => arg.layout.size.bits() <= 128,
+            "x86_64" if spec.rustc_abi != Some(RustcAbi::X86Softfloat) => {
+                arg.layout.size.bits() <= 128
+            }
+            // So far, we haven't implemented this logic for any other target.
+            _ => false,
+        };
+
         for (arg_idx, arg) in self
             .args
             .iter_mut()
@@ -731,12 +750,15 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             .map(|(idx, arg)| (Some(idx), arg))
             .chain(iter::once((None, &mut self.ret)))
         {
-            if arg.is_ignore() {
+            // If the logic above already picked a specific type to cast the argument to, leave that
+            // in place.
+            if matches!(arg.mode, PassMode::Ignore | PassMode::Cast { .. }) {
                 continue;
             }
 
             if arg_idx.is_none()
                 && arg.layout.size > Primitive::Pointer(AddressSpace::DATA).size(cx) * 2
+                && !matches!(arg.layout.backend_repr, BackendRepr::Vector { .. })
             {
                 // Return values larger than 2 registers using a return area
                 // pointer. LLVM and Cranelift disagree about how to return
@@ -746,7 +768,8 @@ impl<'a, Ty> FnAbi<'a, Ty> {
                 // return value independently and decide to pass it in a
                 // register or not, which would result in the return value
                 // being passed partially in registers and partially through a
-                // return area pointer.
+                // return area pointer. For large IR-level values such as `i128`,
+                // cranelift will even split up the value into smaller chunks.
                 //
                 // While Cranelift may need to be fixed as the LLVM behavior is
                 // generally more correct with respect to the surface language,
@@ -776,53 +799,60 @@ impl<'a, Ty> FnAbi<'a, Ty> {
                 // rustc_target already ensure any return value which doesn't
                 // fit in the available amount of return registers is passed in
                 // the right way for the current target.
+                //
+                // The adjustment is not necessary nor desired for types with a vector
+                // representation; those are handled below.
                 arg.make_indirect();
                 continue;
             }
 
             match arg.layout.backend_repr {
-                BackendRepr::Memory { .. } => {}
-
-                // This is a fun case! The gist of what this is doing is
-                // that we want callers and callees to always agree on the
-                // ABI of how they pass SIMD arguments. If we were to *not*
-                // make these arguments indirect then they'd be immediates
-                // in LLVM, which means that they'd used whatever the
-                // appropriate ABI is for the callee and the caller. That
-                // means, for example, if the caller doesn't have AVX
-                // enabled but the callee does, then passing an AVX argument
-                // across this boundary would cause corrupt data to show up.
-                //
-                // This problem is fixed by unconditionally passing SIMD
-                // arguments through memory between callers and callees
-                // which should get them all to agree on ABI regardless of
-                // target feature sets. Some more information about this
-                // issue can be found in #44367.
-                //
-                // Note that the intrinsic ABI is exempt here as
-                // that's how we connect up to LLVM and it's unstable
-                // anyway, we control all calls to it in libstd.
-                BackendRepr::Vector { .. }
-                    if abi != ExternAbi::RustIntrinsic && spec.simd_types_indirect =>
-                {
-                    arg.make_indirect();
-                    continue;
+                BackendRepr::Memory { .. } => {
+                    // Compute `Aggregate` ABI.
+
+                    let is_indirect_not_on_stack =
+                        matches!(arg.mode, PassMode::Indirect { on_stack: false, .. });
+                    assert!(is_indirect_not_on_stack);
+
+                    let size = arg.layout.size;
+                    if arg.layout.is_sized()
+                        && size <= Primitive::Pointer(AddressSpace::DATA).size(cx)
+                    {
+                        // We want to pass small aggregates as immediates, but using
+                        // an LLVM aggregate type for this leads to bad optimizations,
+                        // so we pick an appropriately sized integer type instead.
+                        arg.cast_to(Reg { kind: RegKind::Integer, size });
+                    }
                 }
 
-                _ => continue,
-            }
-            // Compute `Aggregate` ABI.
-
-            let is_indirect_not_on_stack =
-                matches!(arg.mode, PassMode::Indirect { on_stack: false, .. });
-            assert!(is_indirect_not_on_stack);
-
-            let size = arg.layout.size;
-            if !arg.layout.is_unsized() && size <= Primitive::Pointer(AddressSpace::DATA).size(cx) {
-                // We want to pass small aggregates as immediates, but using
-                // an LLVM aggregate type for this leads to bad optimizations,
-                // so we pick an appropriately sized integer type instead.
-                arg.cast_to(Reg { kind: RegKind::Integer, size });
+                BackendRepr::Vector { .. } => {
+                    // This is a fun case! The gist of what this is doing is
+                    // that we want callers and callees to always agree on the
+                    // ABI of how they pass SIMD arguments. If we were to *not*
+                    // make these arguments indirect then they'd be immediates
+                    // in LLVM, which means that they'd used whatever the
+                    // appropriate ABI is for the callee and the caller. That
+                    // means, for example, if the caller doesn't have AVX
+                    // enabled but the callee does, then passing an AVX argument
+                    // across this boundary would cause corrupt data to show up.
+                    //
+                    // This problem is fixed by unconditionally passing SIMD
+                    // arguments through memory between callers and callees
+                    // which should get them all to agree on ABI regardless of
+                    // target feature sets. Some more information about this
+                    // issue can be found in #44367.
+                    //
+                    // Note that the intrinsic ABI is exempt here as those are not
+                    // real functions anyway, and the backend expects very specific types.
+                    if abi != ExternAbi::RustIntrinsic
+                        && spec.simd_types_indirect
+                        && !can_pass_simd_directly(arg)
+                    {
+                        arg.make_indirect();
+                    }
+                }
+
+                _ => {}
             }
         }
     }
diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs
index 5b9414536d8..5f4f4cd57f6 100644
--- a/compiler/rustc_target/src/callconv/x86.rs
+++ b/compiler/rustc_target/src/callconv/x86.rs
@@ -4,7 +4,7 @@ use rustc_abi::{
 };
 
 use crate::callconv::{ArgAttribute, FnAbi, PassMode};
-use crate::spec::HasTargetSpec;
+use crate::spec::{HasTargetSpec, RustcAbi};
 
 #[derive(PartialEq)]
 pub(crate) enum Flavor {
@@ -236,8 +236,16 @@ where
             _ => false, // anyway not passed via registers on x86
         };
         if has_float {
-            if fn_abi.ret.layout.size <= Primitive::Pointer(AddressSpace::DATA).size(cx) {
-                // Same size or smaller than pointer, return in a register.
+            if cx.target_spec().rustc_abi == Some(RustcAbi::X86Sse2)
+                && fn_abi.ret.layout.backend_repr.is_scalar()
+                && fn_abi.ret.layout.size.bits() <= 128
+            {
+                // This is a single scalar that fits into an SSE register, and the target uses the
+                // SSE ABI. We prefer this over integer registers as float scalars need to be in SSE
+                // registers for float operations, so that's the best place to pass them around.
+                fn_abi.ret.cast_to(Reg { kind: RegKind::Vector, size: fn_abi.ret.layout.size });
+            } else if fn_abi.ret.layout.size <= Primitive::Pointer(AddressSpace::DATA).size(cx) {
+                // Same size or smaller than pointer, return in an integer register.
                 fn_abi.ret.cast_to(Reg { kind: RegKind::Integer, size: fn_abi.ret.layout.size });
             } else {
                 // Larger than a pointer, return indirectly.
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
index adee6f5fe99..d3e0a32c8b8 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("macos", Arch::Arm64, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Apple macOS (11.0+, Big Sur+)".into()),
             tier: Some(1),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
index efc42b909e4..183a6c6f2d7 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Apple iOS".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs
index be503d18bf1..ce9ae03e699 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::MacCatalyst);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Apple Mac Catalyst".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs
index 04bbee45cd3..4405e3fec02 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Simulator);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Apple iOS Simulator".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs
index fa0bc130e1c..037685db1b3 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Apple tvOS".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs
index 428045da493..a386220e6fc 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Simulator);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Apple tvOS Simulator".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs
index 9817c5a8eb0..2c1dfdd55ed 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Apple visionOS".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs
index d411f710540..c0b8b409797 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Simulator);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Apple visionOS simulator".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs
index abd924b5934..23596271107 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Apple watchOS".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs
index ba85647fddc..62968f5b555 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetAbi::Simulator);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Apple watchOS Simulator".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
index de6fe991460..87c07cd3109 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
@@ -1,11 +1,11 @@
 use rustc_abi::Endian;
 
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64_be-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Linux (big-endian)".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
index 8fdaff822fe..e785069c78a 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "aarch64_be-unknown-linux-gnu_ilp32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Linux (big-endian, ILP32 ABI)".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs
index 4e1e95ab751..97742403c78 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs
@@ -1,11 +1,11 @@
 use rustc_abi::Endian;
 
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64_be-unknown-netbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 NetBSD (big-endian)".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs b/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs
index 58fc703946e..f58aa1ac043 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs
@@ -1,10 +1,10 @@
-use crate::spec::{RelocModel, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{RelocModel, StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let base = base::solid::opts("asp3");
     Target {
         llvm_target: "aarch64-unknown-none".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 SOLID with TOPPERS/ASP3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs
index a021d317cc8..41c25393e12 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs
@@ -1,4 +1,4 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 // See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
 // for target ABI requirements.
@@ -6,7 +6,7 @@ use crate::spec::{SanitizerSet, StackProbeType, Target, TargetOptions, base};
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64-linux-android".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Android".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs
index 6ac69e0f57f..9b81362b27d 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs
@@ -1,5 +1,6 @@
 use crate::spec::{
-    Cc, LinkerFlavor, Lld, PanicStrategy, RelroLevel, StackProbeType, Target, TargetOptions,
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelroLevel, StackProbeType, Target, TargetMetadata,
+    TargetOptions,
 };
 
 const LINKER_SCRIPT: &str = include_str!("./aarch64_nintendo_switch_freestanding_linker_script.ld");
@@ -8,7 +9,7 @@ const LINKER_SCRIPT: &str = include_str!("./aarch64_nintendo_switch_freestanding
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-none".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Nintendo Switch, Horizon".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs
index 8b96f589c74..a8b133d19bb 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Target, base};
+use crate::spec::{Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_gnullvm::opts();
@@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-pc-windows-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 MinGW (Windows 10+), LLVM ABI".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs
index 14ce5edd2f3..98d78520c98 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Target, base};
+use crate::spec::{Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_msvc::opts();
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-pc-windows-msvc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Windows MSVC".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs
index dd90161f440..7306a75aa22 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs
@@ -1,9 +1,9 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-freebsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 FreeBSD".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs
index df13d52a223..23ed92e62b8 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs
@@ -1,9 +1,9 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-fuchsia".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Fuchsia".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs
index 459e888eb94..580a36cb2e9 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs
@@ -1,9 +1,9 @@
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-hermit".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Hermit".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs
index 699376a7928..1ed4fdb465d 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, SanitizerSet, Target, base};
+use crate::spec::{Cc, LinkerFlavor, SanitizerSet, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::illumos::opts();
@@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
         // LLVM does not currently have a separate illumos target,
         // so we still pass Solaris to it
         llvm_target: "aarch64-unknown-solaris2.11".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 illumos".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs
index 18711cb399d..c6be2c20ea2 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs
@@ -1,9 +1,9 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Linux (kernel 4.1, glibc 2.17+)".into()),
             tier: Some(1),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
index 7b0df7d1130..166bb1ed215 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
@@ -1,9 +1,9 @@
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-linux-gnu_ilp32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Linux (ILP32 ABI)".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
index 4fefdfa5c5e..58ba06e124c 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -17,7 +17,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Linux with musl 1.2.3".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs
index 14a22988a09..f2994b1232e 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs
@@ -1,4 +1,4 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_ohos::opts();
@@ -6,7 +6,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-linux-ohos".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 OpenHarmony".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs
index 0ec76e4b42f..461730457aa 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs
@@ -1,9 +1,9 @@
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-netbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 NetBSD".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs
index 27dd713cc53..6c14f5df466 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs
@@ -8,7 +8,7 @@
 
 use crate::spec::{
     Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target,
-    TargetOptions,
+    TargetMetadata, TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
@@ -31,7 +31,7 @@ pub(crate) fn target() -> Target {
     };
     Target {
         llvm_target: "aarch64-unknown-none".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare ARM64, hardfloat".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs
index 3b719ebaf07..35a4dd72b86 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs
@@ -8,7 +8,7 @@
 
 use crate::spec::{
     Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target,
-    TargetOptions,
+    TargetMetadata, TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
@@ -27,7 +27,7 @@ pub(crate) fn target() -> Target {
     };
     Target {
         llvm_target: "aarch64-unknown-none".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare ARM64, softfloat".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs
index f7f8dc1e1ef..243d84a12ec 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs
@@ -8,7 +8,7 @@
 
 use crate::spec::{
     Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target,
-    TargetOptions, cvs,
+    TargetMetadata, TargetOptions, cvs,
 };
 
 pub(crate) fn target() -> Target {
@@ -33,7 +33,7 @@ pub(crate) fn target() -> Target {
     };
     Target {
         llvm_target: "aarch64-unknown-none".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("AArch64 NuttX".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs
index 0fcf5c34bb0..c23006adad6 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs
@@ -1,9 +1,9 @@
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-openbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 OpenBSD".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs
index 7ff99c574ad..39fe71528d3 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs
@@ -1,4 +1,4 @@
-use crate::spec::{StackProbeType, Target, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::redox::opts();
@@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-redox".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 RedoxOS".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs
index fb8b59f7729..799ff1a806e 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs
@@ -1,4 +1,4 @@
-use crate::spec::{StackProbeType, Target, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::teeos::opts();
@@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-none".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 TEEOS".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs
index cebd8ff2f68..126f0251239 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs
@@ -1,11 +1,13 @@
 // Trusty OS target for AArch64.
 
-use crate::spec::{LinkSelfContainedDefault, PanicStrategy, RelroLevel, Target, TargetOptions};
+use crate::spec::{
+    LinkSelfContainedDefault, PanicStrategy, RelroLevel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-unknown-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Trusty".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs
index 9656024ddaa..327b52389b9 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs
@@ -1,7 +1,7 @@
 // This defines the aarch64 target for UEFI systems as described in the UEFI specification. See the
 // uefi-base module for generic UEFI options.
 
-use crate::spec::{LinkerFlavor, Lld, Target, base};
+use crate::spec::{LinkerFlavor, Lld, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::uefi_msvc::opts();
@@ -12,7 +12,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-windows".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 UEFI".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs
index 3d7c0269808..a40c8c3a3f2 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Target, base};
+use crate::spec::{Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_uwp_msvc::opts();
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-pc-windows-msvc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs
index ac53cbaecce..b6826760183 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs
@@ -1,9 +1,9 @@
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs b/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs
index bb488c350c2..f20782cabb8 100644
--- a/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs
+++ b/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs
@@ -1,11 +1,11 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     Target {
         arch: "amdgpu".into(),
         data_layout: "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9".into(),
         llvm_target: "amdgcn-amd-amdhsa".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("AMD GPU".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
index a5a6f772ac8..4c3a2f43743 100644
--- a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("watchos", Arch::Arm64_32, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64 Apple watchOS with 32-bit pointers".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs
index 744d95445b8..79b95dbde52 100644
--- a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("macos", Arch::Arm64e, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64e Apple Darwin".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs
index dace11dae24..848dbeec199 100644
--- a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("ios", Arch::Arm64e, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64e Apple iOS".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs
index 2ccdc76c52e..3dbe169e826 100644
--- a/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("tvos", Arch::Arm64e, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARM64e Apple tvOS".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs
index 5026c52429e..bb3e3e544cb 100644
--- a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Lld, Target, add_link_args, base};
+use crate::spec::{LinkerFlavor, Lld, Target, TargetMetadata, add_link_args, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_msvc::opts();
@@ -12,7 +12,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "arm64ec-pc-windows-msvc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Arm64EC Windows MSVC".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs
index 73fb02c6731..d74468899f5 100644
--- a/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, SanitizerSet, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "arm-linux-androideabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv6 Android".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs
index 87e790a1f39..3b6c97167cf 100644
--- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "arm-unknown-linux-gnueabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv6 Linux (kernel 3.2, glibc 2.17)".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs
index 6470bf6b611..a3f5389f0aa 100644
--- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "arm-unknown-linux-gnueabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17)".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs
index 26241dd0bd4..3919a5e0771 100644
--- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "arm-unknown-linux-musleabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv6 Linux with musl 1.2.3".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs
index 4bbde7667b9..ca52e5b3ca6 100644
--- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "arm-unknown-linux-musleabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv6 Linux with musl 1.2.3, hardfloat".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs
index 60ec4edbb0d..afb17fd8203 100644
--- a/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs
@@ -1,11 +1,11 @@
 use rustc_abi::Endian;
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armeb-unknown-linux-gnueabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Arm BE8 the default Arm big-endian architecture since Armv6".into()),
             tier: Some(3),
             host_tools: None, // ?
diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
index 18b93f6cbc4..d227d63c4a3 100644
--- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
@@ -3,13 +3,14 @@
 use rustc_abi::Endian;
 
 use crate::spec::{
-    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armebv7r-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare Armv7-R, Big Endian".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
index 6c22cd34fc3..c373afb914e 100644
--- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
@@ -3,13 +3,14 @@
 use rustc_abi::Endian;
 
 use crate::spec::{
-    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armebv7r-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare Armv7-R, Big Endian, hardfloat".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs
index dc8cb4fb187..9571821656c 100644
--- a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs
@@ -10,13 +10,14 @@
 //! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
 
 use crate::spec::{
-    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions, cvs,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv4t-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare Armv4T".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs
index 081132b0e68..beaec71093c 100644
--- a/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv4t-unknown-linux-gnueabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv4T Linux".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs
index e0a4f26f0a6..75ab941c5cf 100644
--- a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs
@@ -1,11 +1,11 @@
 //! Targets the ARMv5TE, with code as `a32` code by default.
 
-use crate::spec::{FloatAbi, FramePointer, Target, TargetOptions, base, cvs};
+use crate::spec::{FloatAbi, FramePointer, Target, TargetMetadata, TargetOptions, base, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv5te-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare Armv5TE".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs
index ce7060b3847..52e786de3ed 100644
--- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv5te-unknown-linux-gnueabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv5TE Linux (kernel 4.4, glibc 2.23)".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs
index 62619546891..e675739629b 100644
--- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv5te-unknown-linux-musleabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv5TE Linux with musl 1.2.3".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs
index 73013bf00b1..dbe1540364a 100644
--- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv5te-unknown-linux-uclibcgnueabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv5TE Linux with uClibc".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs
index 4bbc514f2b3..1625a6b84bb 100644
--- a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv6-unknown-freebsd-gnueabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv6 FreeBSD".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs
index 6b9d3ccd215..af9a4359565 100644
--- a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv6-unknown-netbsdelf-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv6 NetBSD w/hard-float".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs
index 5438811803b..4c32a5e6216 100644
--- a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs
+++ b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, FloatAbi, LinkerFlavor, Lld, RelocModel, Target, TargetOptions, cvs};
+use crate::spec::{
+    Cc, FloatAbi, LinkerFlavor, Lld, RelocModel, Target, TargetMetadata, TargetOptions, cvs,
+};
 
 /// A base target for Nintendo 3DS devices using the devkitARM toolchain.
 ///
@@ -12,7 +14,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "armv6k-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs
index e1cead9e0b7..706fb12a524 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, FloatAbi, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, FloatAbi, LinkerFlavor, Lld, SanitizerSet, Target, TargetMetadata, TargetOptions, base,
+};
 
 // This target if is for the baseline of the Android v7a ABI
 // in thumb mode. It's named armv7-* instead of thumbv7-*
@@ -13,7 +15,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-march=armv7-a"]);
     Target {
         llvm_target: "armv7-none-linux-android".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A Android".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs
index 4e8a9d55f9a..c17db36ee61 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs
@@ -1,11 +1,12 @@
 use crate::spec::{
-    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions, cvs,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7 RTEMS (Requires RTEMS toolchain and kernel".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs
index 4b2ab8b8f20..5d292bbf8ad 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, FloatAbi, LinkerFlavor, Lld, RelocModel, Target, TargetOptions, cvs};
+use crate::spec::{
+    Cc, FloatAbi, LinkerFlavor, Lld, RelocModel, Target, TargetMetadata, TargetOptions, cvs,
+};
 
 /// A base target for PlayStation Vita devices using the VITASDK toolchain (using newlib).
 ///
@@ -14,7 +16,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "thumbv7a-vita-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some(
                 "Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)".into(),
             ),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs
index 34f118d4f5d..56f2e090e07 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-freebsd-gnueabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A FreeBSD".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs
index bb28427c99b..603afe2c48b 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 // This target is for glibc Linux on ARMv7 without thumb-mode, NEON or
 // hardfloat.
@@ -6,7 +6,7 @@ use crate::spec::{FloatAbi, Target, TargetOptions, base};
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-gnueabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A Linux (kernel 4.15, glibc 2.27)".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs
index 6bffc0da87b..3b5a337b4f1 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 // This target is for glibc Linux on ARMv7 without NEON or
 // thumb-mode. See the thumbv7neon variant for enabling both.
@@ -6,7 +6,7 @@ use crate::spec::{FloatAbi, Target, TargetOptions, base};
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17)".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs
index 0436e0d8df4..42fbf6f4861 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 // This target is for musl Linux on ARMv7 without thumb-mode, NEON or
 // hardfloat.
@@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
     // target.
     Target {
         llvm_target: "armv7-unknown-linux-musleabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A Linux with musl 1.2.3".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs
index 22e49f2f1b0..a3ac0223c84 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs
@@ -1,11 +1,11 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 // This target is for musl Linux on ARMv7 without thumb-mode or NEON.
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-musleabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A Linux with musl 1.2.3, hardfloat".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs
index d1261202124..f31dedb04e6 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs
@@ -1,4 +1,4 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 // This target is for OpenHarmony on ARMv7 Linux with thumb-mode, but no NEON or
 // hardfloat.
@@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
     // target.
     Target {
         llvm_target: "armv7-unknown-linux-ohos".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A OpenHarmony".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs
index ffcd8876eb4..a9e9f4651bb 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 // This target is for uclibc Linux on ARMv7 without NEON,
 // thumb-mode or hardfloat.
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
     let base = base::linux_uclibc::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A Linux with uClibc, softfloat".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs
index 586bd8d3d88..a95f12d0230 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 // This target is for uclibc Linux on ARMv7 without NEON or
 // thumb-mode. See the thumbv7neon variant for enabling both.
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
     let base = base::linux_uclibc::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A Linux with uClibc, hardfloat".into()),
             tier: Some(3),
             host_tools: None, // ?
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs
index 28d3d572bf3..d155dc58e51 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-netbsdelf-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A NetBSD w/hard-float".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs
index b86c788df15..31d492e83cd 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs
@@ -1,5 +1,6 @@
 use crate::spec::{
-    FloatAbi, LinkSelfContainedDefault, PanicStrategy, RelroLevel, Target, TargetOptions,
+    FloatAbi, LinkSelfContainedDefault, PanicStrategy, RelroLevel, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
@@ -8,7 +9,7 @@ pub(crate) fn target() -> Target {
         // to determine the calling convention and float ABI, and it doesn't
         // support the "musleabi" value.
         llvm_target: "armv7-unknown-unknown-gnueabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A Trusty".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs
index 212c45424db..05be389b57c 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A for VxWorks".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
index 2ed10045412..26c25139989 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
@@ -1,10 +1,10 @@
-use crate::spec::{FloatAbi, RelocModel, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, RelocModel, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let base = base::solid::opts("asp3");
     Target {
         llvm_target: "armv7a-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Arm SOLID with TOPPERS/ASP3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
index c9c15b402ae..7032444bea4 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
@@ -1,10 +1,10 @@
-use crate::spec::{FloatAbi, RelocModel, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, RelocModel, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let base = base::solid::opts("asp3");
     Target {
         llvm_target: "armv7a-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Arm SOLID with TOPPERS/ASP3, hardfloat".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs
index d59849ec2c4..fb1d7d6c39d 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs
@@ -15,7 +15,8 @@
 // linking. rationale: matches `thumb` targets
 
 use crate::spec::{
-    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
@@ -35,7 +36,7 @@ pub(crate) fn target() -> Target {
     };
     Target {
         llvm_target: "armv7a-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare Armv7-A".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs
index 06481e6f882..df3a76599a7 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs
@@ -6,7 +6,8 @@
 // `thumb` & `aarch64` targets.
 
 use crate::spec::{
-    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
@@ -27,7 +28,7 @@ pub(crate) fn target() -> Target {
     };
     Target {
         llvm_target: "armv7a-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare Armv7-A, hardfloat".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs
index 08cbfc74396..052285b98dc 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs
@@ -5,7 +5,8 @@
 // configuration without hardware floating point support.
 
 use crate::spec::{
-    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions, cvs,
 };
 
 pub(crate) fn target() -> Target {
@@ -27,7 +28,7 @@ pub(crate) fn target() -> Target {
     };
     Target {
         llvm_target: "armv7a-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARMv7-A Cortex-A with NuttX".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs
index f68c11a9c68..85543e95616 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs
@@ -5,7 +5,8 @@
 // configuration with hardware floating point support.
 
 use crate::spec::{
-    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions, cvs,
 };
 
 pub(crate) fn target() -> Target {
@@ -27,7 +28,7 @@ pub(crate) fn target() -> Target {
     };
     Target {
         llvm_target: "armv7a-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARMv7-A Cortex-A with NuttX (hard float)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs
index e232f54f9b3..8103d132cea 100644
--- a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("watchos", Arch::Armv7k, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-A Apple WatchOS".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs
index 1eda0545169..334be483daa 100644
--- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs
@@ -1,13 +1,14 @@
 // Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
 
 use crate::spec::{
-    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv7r-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-R".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs
index d4e85bc9b0a..2bb3e70483a 100644
--- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs
@@ -1,13 +1,14 @@
 // Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
 
 use crate::spec::{
-    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv7r-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Armv7-R, hardfloat".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs
index 1c3040de06e..ba9edd71461 100644
--- a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("ios", Arch::Armv7s, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("ARMv7-A Apple-A6 Apple iOS".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs
index 3df42a1482c..8cf1ff95751 100644
--- a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs
@@ -1,13 +1,14 @@
 // Targets the Little-endian Cortex-R52 processor (ARMv8-R)
 
 use crate::spec::{
-    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv8r-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare Armv8-R, hardfloat".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs b/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs
index b95f93c3553..3d39cd26c65 100644
--- a/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs
@@ -1,11 +1,11 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Target, base};
+use crate::spec::{Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "bpfeb".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("BPF (big endian)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs b/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs
index 711bbb04b19..51f45b01244 100644
--- a/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs
@@ -1,11 +1,11 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Target, base};
+use crate::spec::{Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "bpfel".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("BPF (little endian)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs
index c90d3bcc6ae..6142c1541f0 100644
--- a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs
+++ b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base};
 
 // This target is for glibc Linux on Csky
 
@@ -6,7 +6,7 @@ pub(crate) fn target() -> Target {
     Target {
         //https://github.com/llvm/llvm-project/blob/8b76aea8d8b1b71f6220bc2845abc749f18a19b7/clang/lib/Basic/Targets/CSKY.h
         llvm_target: "csky-unknown-linux-gnuabiv2".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("C-SKY abiv2 Linux (little endian)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs
index d0583b7866b..c233ec3ada7 100644
--- a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs
+++ b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base};
 
 // This target is for glibc Linux on Csky
 
@@ -6,7 +6,7 @@ pub(crate) fn target() -> Target {
     Target {
         //https://github.com/llvm/llvm-project/blob/8b76aea8d8b1b71f6220bc2845abc749f18a19b7/clang/lib/Basic/Targets/CSKY.h
         llvm_target: "csky-unknown-linux-gnuabiv2".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("C-SKY abiv2 Linux, hardfloat (little endian)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs
index 003600c26cc..f7416a7e0fd 100644
--- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -15,7 +15,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "hexagon-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Hexagon Linux with musl 1.2.3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs
index 730b19abd2b..e5a927d0953 100644
--- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs
@@ -1,9 +1,9 @@
-use crate::spec::{PanicStrategy, Target, TargetOptions};
+use crate::spec::{PanicStrategy, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "hexagon-unknown-none-elf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare Hexagon (v60+, HVX)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs
index 41c5fafe341..29865fcd4c4 100644
--- a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs
@@ -1,5 +1,5 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     // i386-apple-ios is a simulator target, even though it isn't declared
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("ios", Arch::I386, TargetAbi::Simulator);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("x86 Apple iOS Simulator".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs
index dd38f86bced..394e6f9e6bf 100644
--- a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs
@@ -2,6 +2,7 @@ use crate::spec::Target;
 
 pub(crate) fn target() -> Target {
     let mut base = super::i686_pc_windows_msvc::target();
+    base.rustc_abi = None; // overwrite the SSE2 ABI set by the base target
     base.cpu = "pentium".into();
     base.llvm_target = "i586-pc-windows-msvc".into();
     base
diff --git a/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs
index 6aa34f157ab..39a71cf1781 100644
--- a/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::netbsd::opts();
@@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i586-unknown-netbsdelf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit x86, resricted to Pentium".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs
index 29ef8b883a1..08281eda42e 100644
--- a/compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::redox::opts();
@@ -11,12 +11,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i586-unknown-redox".into(),
-        metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
-        },
+        metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None },
         pointer_width: 32,
         data_layout:
             "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128"
diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs
index 6adf690e0dd..161db9a08bb 100644
--- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("macos", Arch::I686, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("x86 Apple macOS (10.12+, Sierra+)".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs
index 7d61d5ca257..f2d7ec66443 100644
--- a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs
@@ -1,4 +1,6 @@
-use crate::spec::{RustcAbi, SanitizerSet, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    RustcAbi, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 // See https://developer.android.com/ndk/guides/abis.html#x86
 // for target ABI requirements.
@@ -16,7 +18,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-linux-android".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit x86 Android".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
index 06dbf1e3a16..2a26323e514 100644
--- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, base};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_gnu::opts();
@@ -18,7 +18,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-pc-windows-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit MinGW (Windows 10+)".into()),
             tier: Some(1),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs
index 05d848e0393..2e2ea8f81be 100644
--- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, base};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_gnullvm::opts();
@@ -17,7 +17,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-pc-windows-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit x86 MinGW (Windows 10+), LLVM ABI".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs
index e0e47113087..6a95afa1d0d 100644
--- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Lld, RustcAbi, SanitizerSet, Target, base};
+use crate::spec::{LinkerFlavor, Lld, RustcAbi, SanitizerSet, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_msvc::opts();
@@ -22,7 +22,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-pc-windows-msvc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit MSVC (Windows 10+)".into()),
             tier: Some(1),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs
index 71c26041a50..1dfea64ebed 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::freebsd::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-freebsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit FreeBSD".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs
index 464ac46b07c..ab329170a4f 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::haiku::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-haiku".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit Haiku".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs
index 2f93e97d9fc..b01f93f7404 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::hurd_gnu::opts();
@@ -9,7 +9,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-hurd-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit GNU/Hurd".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs
index fe699dbcb51..c70c026f9f7 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, RustcAbi, SanitizerSet, StackProbeType, Target, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, RustcAbi, SanitizerSet, StackProbeType, Target, TargetMetadata, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -22,7 +24,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit Linux (kernel 3.2, glibc 2.17+)".into()),
             tier: Some(1),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs
index 3d25c951e81..47a7eb3d597 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, base};
+use crate::spec::{
+    Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, TargetMetadata, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -28,7 +30,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit Linux with musl 1.2.3".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs
index 4bc6eee1ac2..cbd61cadb36 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::netbsd::opts();
@@ -10,7 +12,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-netbsdelf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("NetBSD/i386 with SSE2".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs
index a3bdf66a14d..48f7be7dc2b 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::openbsd::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-openbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit OpenBSD".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs
index 736b9131022..1a7923ca89b 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs
@@ -5,7 +5,7 @@
 // The cdecl ABI is used. It differs from the stdcall or fastcall ABI.
 // "i686-unknown-windows" is used to get the minimal subset of windows-specific features.
 
-use crate::spec::{LinkerFlavor, Lld, RustcAbi, Target, add_link_args, base};
+use crate::spec::{LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, add_link_args, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::uefi_msvc::opts();
@@ -86,7 +86,7 @@ pub(crate) fn target() -> Target {
     // remove -gnu and use the default one.
     Target {
         llvm_target: "i686-unknown-windows-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit UEFI".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs
index 0e1b65ef598..d95f779774f 100644
--- a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, base};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_uwp_gnu::opts();
@@ -17,7 +17,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-pc-windows-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs
index 44cf9b1adda..fa7a103df79 100644
--- a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{RustcAbi, Target, base};
+use crate::spec::{RustcAbi, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_uwp_msvc::opts();
@@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-pc-windows-msvc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs
index e9100da14cb..f364c2cb032 100644
--- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, base};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_gnu::opts();
@@ -19,7 +19,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-pc-windows-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit MinGW (Windows 7+)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
index 94284a2fe72..233a1c4fd7a 100644
--- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Lld, RustcAbi, SanitizerSet, Target, base};
+use crate::spec::{LinkerFlavor, Lld, RustcAbi, SanitizerSet, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_msvc::opts();
@@ -23,7 +23,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-pc-windows-msvc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit MSVC (Windows 7+)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs
index 4e801955d0c..63ede7b4ab8 100644
--- a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::vxworks::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
index 603c0f99314..9e743a35529 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
@@ -1,9 +1,9 @@
-use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions, base};
+use crate::spec::{CodeModel, SanitizerSet, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "loongarch64-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36)".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
index d7044dde0f1..d9010b1e4ee 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
@@ -1,9 +1,9 @@
-use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions, base};
+use crate::spec::{CodeModel, SanitizerSet, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "loongarch64-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("LoongArch64 Linux (LP64D ABI) with musl 1.2.5".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs
index 11d05db6b0a..c1c859ef25c 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs
@@ -1,9 +1,9 @@
-use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions, base};
+use crate::spec::{CodeModel, SanitizerSet, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "loongarch64-unknown-linux-ohos".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("LoongArch64 OpenHarmony".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
index db527c8b636..91e3064aaed 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
@@ -1,11 +1,12 @@
 use crate::spec::{
-    Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
+    Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "loongarch64-unknown-none".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Freestanding/bare-metal LoongArch64".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
index 221ca02fe3e..24983900683 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
@@ -1,11 +1,12 @@
 use crate::spec::{
-    Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
+    Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "loongarch64-unknown-none".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Freestanding/bare-metal LoongArch64 softfloat".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs
index d3584a1be74..9bd02e842c2 100644
--- a/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{LinkSelfContainedDefault, Target, TargetOptions, base};
+use crate::spec::{LinkSelfContainedDefault, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -9,7 +9,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "m68k-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Motorola 680x0 Linux".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/m68k_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/m68k_unknown_none_elf.rs
index 8b8693b55c5..6b66052692a 100644
--- a/compiler/rustc_target/src/spec/targets/m68k_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/m68k_unknown_none_elf.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{CodeModel, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{CodeModel, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let options = TargetOptions {
@@ -20,7 +20,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "m68k".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Motorola 680x0".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs
index 4880e993722..1300280e35b 100644
--- a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs
@@ -2,7 +2,7 @@
 
 use rustc_abi::Endian;
 
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
     Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS64 for OpenWrt Linux musl 1.2.3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs
index daf6d5de4c0..b130ca29c7f 100644
--- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs
@@ -1,11 +1,11 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mips64-unknown-linux-gnuabi64".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS64 Linux, N64 ABI (kernel 4.4, glibc 2.23)".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs
index 03c8fa92450..4ea7c7bff44 100644
--- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
     Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS64 Linux, N64 ABI, musl 1.2.3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs
index c7d24871225..a9afea27ef3 100644
--- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs
@@ -1,9 +1,9 @@
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mips64el-unknown-linux-gnuabi64".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS64 Linux, N64 ABI (kernel 4.4, glibc 2.23)".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
index 5e7c37fd46c..7bdd9edda70 100644
--- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
     Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64el-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS64 Linux, N64 ABI, musl 1.2.3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs b/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs
index 2815d995c31..def12122416 100644
--- a/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs
@@ -1,12 +1,14 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
         llvm_target: "mips".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS32r2 BE Baremetal Softfloat".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs
index 19cf62d19f6..29a451b31a6 100644
--- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs
@@ -1,11 +1,11 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mips-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS Linux (kernel 4.4, glibc 2.23)".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs
index dbca90ba569..82f2fda7fff 100644
--- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -9,7 +9,7 @@ pub(crate) fn target() -> Target {
     base.max_atomic_width = Some(32);
     Target {
         llvm_target: "mips-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS Linux with musl 1.2.3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs
index c26c7867ec7..0955b3debea 100644
--- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs
@@ -1,11 +1,11 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mips-unknown-linux-uclibc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS Linux with uClibc".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs b/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs
index f532643b56a..cc9c19e4a0b 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs
@@ -1,12 +1,14 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
         llvm_target: "mipsel".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS32r2 LE Baremetal Softfloat".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs
index 2c63b0f2f38..37ebb3d174b 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions, cvs};
+use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetMetadata, TargetOptions, cvs};
 
 // The PSP has custom linker requirements.
 const LINKER_SCRIPT: &str = include_str!("./mipsel_sony_psp_linker_script.ld");
@@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "mipsel-sony-psp".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS (LE) Sony PlatStation Portable (PSP)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs
index 1b8f9b71e93..8475a43ea63 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs
@@ -1,9 +1,11 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mipsel-sony-psx".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS (LE) Sony PlayStation 1 (PSX)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs
index 08226449358..6c7ea5c5688 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs
@@ -1,9 +1,9 @@
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mipsel-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS (little endian) Linux (kernel 4.4, glibc 2.23)".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs
index 339b32b6339..d008bb55189 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
     base.max_atomic_width = Some(32);
     Target {
         llvm_target: "mipsel-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS (little endian) Linux with musl 1.2.3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs
index 88474e71848..08c4347fe01 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs
@@ -1,9 +1,9 @@
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mipsel-unknown-linux-uclibc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("MIPS (LE) Linux with uClibc".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs
index 400e05f1478..502d7382b3c 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::netbsd::opts();
@@ -9,7 +9,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "mipsel-unknown-netbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit MIPS (LE), requires mips32 cpu support".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs
index bb8eb24908c..6a201c56475 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs
@@ -2,12 +2,14 @@
 //!
 //! Can be used for MIPS M4K core (e.g. on PIC32MX devices)
 
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mipsel-unknown-none".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare MIPS (LE) softfloat".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs
index c7b0a05d889..0716f2e483b 100644
--- a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs
@@ -1,11 +1,11 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mipsisa32r6-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit MIPS Release 6 Big Endian".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs
index c75023385c2..81f2424e4de 100644
--- a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs
@@ -1,9 +1,9 @@
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mipsisa32r6el-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit MIPS Release 6 Little Endian".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs
index 49bec90022c..3eefa27ea04 100644
--- a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs
@@ -1,11 +1,11 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mipsisa64r6-unknown-linux-gnuabi64".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit MIPS Release 6 Big Endian".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs
index 60bda7a5996..0887180791c 100644
--- a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs
@@ -1,9 +1,9 @@
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "mipsisa64r6el-unknown-linux-gnuabi64".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit MIPS Release 6 Little Endian".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs
index 80cb740450a..b067ac1e54a 100644
--- a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs
@@ -1,9 +1,11 @@
-use crate::spec::{Cc, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions, cvs};
+use crate::spec::{
+    Cc, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "msp430-none-elf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("16-bit MSP430 microcontrollers".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs
index 80bfa358243..598f0f19f0d 100644
--- a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs
@@ -1,5 +1,6 @@
 use crate::spec::{
-    LinkSelfContainedDefault, LinkerFlavor, MergeFunctions, PanicStrategy, Target, TargetOptions,
+    LinkSelfContainedDefault, LinkerFlavor, MergeFunctions, PanicStrategy, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
@@ -7,7 +8,7 @@ pub(crate) fn target() -> Target {
         arch: "nvptx64".into(),
         data_layout: "e-p6:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64".into(),
         llvm_target: "nvptx64-nvidia-cuda".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("--emit=asm generates PTX code that runs on NVIDIA GPUs".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs
index 2125c95e266..a1405188999 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::aix::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64-ibm-aix".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit AIX (7.2 and newer)".into()),
             tier: Some(3),
             host_tools: Some(false),
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 201ab0d534f..dba45776c94 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::freebsd::opts();
@@ -11,7 +13,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64-unknown-freebsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("PPC64 FreeBSD (ELFv2)".into()),
             tier: Some(3),
             host_tools: Some(true),
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 1a2f2125942..1f67bc7f3c2 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
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -11,7 +13,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("PowerPC Linux (kernel 3.2, glibc 2.17)".into()),
             tier: Some(2),
             host_tools: Some(true),
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 417c8b63c86..49413d27a45 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
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -13,7 +15,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit PowerPC Linux with musl 1.2.3".into()),
             tier: Some(3),
             host_tools: Some(false),
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 15947fdb0ac..f5ca54291c6 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::openbsd::opts();
@@ -11,7 +13,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64-unknown-openbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("OpenBSD/powerpc64".into()),
             tier: Some(3),
             host_tools: Some(true),
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 d48c2f5e744..3e4a58f568a 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::vxworks::opts();
@@ -11,7 +13,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
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 13885c7326a..4640d537e8e 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::freebsd::opts();
@@ -9,7 +11,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64le-unknown-freebsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("PPC64LE FreeBSD".into()),
             tier: Some(3),
             host_tools: Some(true),
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 06ae54063ce..dd3f660d81e 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
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -9,7 +11,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("PPC64LE Linux (kernel 3.10, glibc 2.17)".into()),
             tier: Some(2),
             host_tools: Some(true),
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 f763c37f535..9e2bfe2c56f 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
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -11,7 +13,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64le-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit PowerPC Linux with musl 1.2.3, Little Endian".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs
index d6a84f55f5e..5e1161e2f7d 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::freebsd::opts();
@@ -14,7 +16,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-freebsd13.0".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("PowerPC FreeBSD".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs
index 6f3a2baf405..6cde4bd98ac 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -10,7 +12,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("PowerPC Linux (kernel 3.2, glibc 2.17)".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs
index c4d894823e6..03bae9b5977 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -10,7 +12,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("PowerPC SPE Linux".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs
index 5b5fea666bb..316b62d941b 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -12,7 +14,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("PowerPC Linux with musl 1.2.3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs
index dfd99635ddd..df4fd75b0bd 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -12,7 +14,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-linux-muslspe".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("PowerPC SPE Linux with musl".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs
index 7492077bb88..47a61a1aff2 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::netbsd::opts();
@@ -10,7 +12,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-netbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("NetBSD 32-bit powerpc systems".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs
index dd82a6a71cd..bc5a50a0539 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{StackProbeType, Target, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::openbsd::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-openbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs
index c4f93c60d3e..ca78be2b2b2 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::vxworks::opts();
@@ -10,7 +12,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs
index 0284c50bd65..e6345629f03 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::vxworks::opts();
@@ -10,7 +12,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs
index 4d3df78a563..55dc6a70627 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs
@@ -1,9 +1,9 @@
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs
index 771ffac7d80..00e8532d238 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     let abi = "ilp32e";
@@ -7,7 +9,7 @@ pub(crate) fn target() -> Target {
         // `options.llvm_abiname`.
         data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare RISC-V (RV32E ISA)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs
index 3b81c278d3a..f814201601f 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     let abi = "ilp32e";
@@ -7,7 +9,7 @@ pub(crate) fn target() -> Target {
         // `options.llvm_abiname`.
         data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare RISC-V (RV32EM ISA)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs
index c18b51ad46e..33df429db72 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     let abi = "ilp32e";
@@ -7,7 +9,7 @@ pub(crate) fn target() -> Target {
         // `options.llvm_abiname`.
         data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare RISC-V (RV32EMC ISA)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs
index e9c57b99b92..6dda346aaaf 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs
@@ -1,11 +1,11 @@
 use std::borrow::Cow;
 
-use crate::spec::{CodeModel, SplitDebuginfo, Target, TargetOptions, base};
+use crate::spec::{CodeModel, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv32-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V Linux (kernel 5.4, glibc 2.33)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs
index a07429bb0c5..ba10e3c6881 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs
@@ -1,11 +1,11 @@
 use std::borrow::Cow;
 
-use crate::spec::{CodeModel, SplitDebuginfo, Target, TargetOptions, base};
+use crate::spec::{CodeModel, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv32-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some(
                 "RISC-V Linux (kernel 5.4, musl 1.2.3 + RISCV32 support patches".into(),
             ),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
index 0e0e13fd1d8..f9a3b217220 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
@@ -1,10 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare RISC-V (RV32I ISA)".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
index 669c1702fda..162f21c42ba 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
@@ -1,10 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC Zero's zero-knowledge Virtual Machine (RV32IM ISA)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
index 477a6c0e9eb..47b408a12d1 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
@@ -1,10 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
index 68146788d20..a173fb00b32 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
@@ -1,10 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare RISC-V (RV32IMA ISA)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
index e12c3af6f8f..48db9f44eac 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
@@ -1,10 +1,10 @@
-use crate::spec::{PanicStrategy, RelocModel, Target, TargetOptions, cvs};
+use crate::spec::{PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V ESP-IDF".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
index adc76f3cdb5..1608f051ea8 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
@@ -1,10 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare RISC-V (RV32IMAC ISA)".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
index 3eb3d18faf4..4ee02c6b295 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
@@ -1,10 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
index 88d112a012d..0893bd5ad6d 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
@@ -1,10 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V Xous (RV32IMAC ISA)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs
index 0d5eda708d1..0929af7bb75 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs
@@ -1,10 +1,10 @@
-use crate::spec::{PanicStrategy, RelocModel, Target, TargetOptions, cvs};
+use crate::spec::{PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V ESP-IDF".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs
index 7395e1a6aad..44a84d9082c 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs
@@ -1,10 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare RISC-V (RV32IMAFC ISA)".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs
index 7864f7f8f9a..8908c0c53d9 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs
@@ -1,10 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
index cec97f86538..82a4d58a398 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
@@ -1,10 +1,10 @@
-use crate::spec::{PanicStrategy, RelocModel, Target, TargetOptions, cvs};
+use crate::spec::{PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V ESP-IDF".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
index 0e00fc69b41..755ffc6154a 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
@@ -1,10 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare RISC-V (RV32IMC ISA)".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
index 60d8ec576af..8da0b0e3e6b 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
@@ -1,10 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
index f694a1cb60d..c8ef737b9e7 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
@@ -1,11 +1,13 @@
 use std::borrow::Cow;
 
-use crate::spec::{CodeModel, SanitizerSet, SplitDebuginfo, Target, TargetOptions, base};
+use crate::spec::{
+    CodeModel, SanitizerSet, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv64-linux-android".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V 64-bit Android".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs
index 720549e6a01..58ded24b9c5 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs
@@ -1,9 +1,9 @@
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv64".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs
index 905bed76db4..ecf65677531 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs
@@ -1,9 +1,9 @@
-use crate::spec::{CodeModel, Target, TargetOptions, base};
+use crate::spec::{CodeModel, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-freebsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V FreeBSD".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
index 7a887b604c5..d673936f5f8 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
@@ -1,9 +1,9 @@
-use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions, base};
+use crate::spec::{CodeModel, SanitizerSet, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-fuchsia".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V Fuchsia".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs
index a24e24edc59..88b5dca284a 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs
@@ -1,9 +1,9 @@
-use crate::spec::{CodeModel, RelocModel, Target, TargetOptions, TlsModel, base};
+use crate::spec::{CodeModel, RelocModel, Target, TargetMetadata, TargetOptions, TlsModel, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-hermit".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V Hermit".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs
index da2c272005d..8ffb622511d 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs
@@ -1,11 +1,11 @@
 use std::borrow::Cow;
 
-use crate::spec::{CodeModel, SplitDebuginfo, Target, TargetOptions, base};
+use crate::spec::{CodeModel, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V Linux (kernel 4.20, glibc 2.29)".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
index 0a4cc3b8be6..33b08fdcb05 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
@@ -1,11 +1,11 @@
 use std::borrow::Cow;
 
-use crate::spec::{CodeModel, SplitDebuginfo, Target, TargetOptions, base};
+use crate::spec::{CodeModel, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V Linux (kernel 4.20, musl 1.2.3)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs
index 9edec38f652..2b647e36f18 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs
@@ -1,9 +1,9 @@
-use crate::spec::{CodeModel, Target, TargetOptions, base};
+use crate::spec::{CodeModel, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-netbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("RISC-V NetBSD".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs
index c32c57d92f7..d6f0a5499b9 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs
@@ -1,12 +1,12 @@
 use crate::spec::{
     Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target,
-    TargetOptions,
+    TargetMetadata, TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare RISC-V (RV64IMAFDC ISA)".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs
index 2cbb8c19b84..bc6829897a4 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs
@@ -1,12 +1,12 @@
 use crate::spec::{
     Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target,
-    TargetOptions, cvs,
+    TargetMetadata, TargetOptions, cvs,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs
index 6aacb04418e..75f508d8e93 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs
@@ -1,9 +1,9 @@
-use crate::spec::{CodeModel, Target, TargetOptions, base};
+use crate::spec::{CodeModel, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-openbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("OpenBSD/riscv64".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
index d62ecc07a5d..5c5d4aa32a2 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
@@ -1,13 +1,13 @@
 use crate::spec::{
     Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target,
-    TargetOptions,
+    TargetMetadata, TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
         llvm_target: "riscv64".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare RISC-V (RV64IMAC ISA)".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
index 306b23d2787..0928250dba6 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
@@ -1,12 +1,12 @@
 use crate::spec::{
     Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target,
-    TargetOptions, cvs,
+    TargetMetadata, TargetOptions, cvs,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
index 41aa400f3e0..e0d16a7bfa5 100644
--- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{SanitizerSet, StackProbeType, Target, base};
+use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -15,7 +15,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "s390x-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("S390x Linux (kernel 3.2, glibc 2.17)".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
index 61c01eba70d..47050c1f769 100644
--- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{SanitizerSet, StackProbeType, Target, base};
+use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -18,7 +18,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "s390x-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("S390x Linux (kernel 3.2, musl 1.2.3)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs
index 3317fe51c33..a52dadba5a5 100644
--- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Target, base};
+use crate::spec::{Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "sparc64-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("SPARC Linux (kernel 4.4, glibc 2.23)".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs
index 4c2b971c0f1..21eedc5b6bc 100644
--- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::netbsd::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "sparc64-unknown-netbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("NetBSD/sparc64".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs
index 81d7bf9a628..b573bdf80a9 100644
--- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::openbsd::opts();
@@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "sparc64-unknown-openbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("OpenBSD/sparc64".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs
index 6abef79be96..ffef6967912 100644
--- a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs
@@ -1,11 +1,11 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "sparc-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("32-bit SPARC Linux".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
index 00cd7438f7e..c2f64998ddd 100644
--- a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
@@ -1,6 +1,8 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
+};
 
 pub(crate) fn target() -> Target {
     let options = TargetOptions {
@@ -20,7 +22,7 @@ pub(crate) fn target() -> Target {
     Target {
         data_layout: "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64".into(),
         llvm_target: "sparc-unknown-none-elf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare 32-bit SPARC V7+".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs
index 5b7d560a8e0..1c53e15837c 100644
--- a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{Cc, LinkerFlavor, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::solaris::opts();
@@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "sparcv9-sun-solaris".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("SPARC Solaris 11.4".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs
index b0eefcab209..7221bd8d4ae 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs
@@ -10,13 +10,14 @@
 //! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
 
 use crate::spec::{
-    FloatAbi, FramePointer, PanicStrategy, RelocModel, Target, TargetOptions, base, cvs,
+    FloatAbi, FramePointer, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, base,
+    cvs,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv4t-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Thumb-mode Bare ARMv4T".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs
index 1439e4a939f..155e25211c1 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs
@@ -1,11 +1,11 @@
 //! Targets the ARMv5TE, with code as `t32` code by default.
 
-use crate::spec::{FloatAbi, FramePointer, Target, TargetOptions, base, cvs};
+use crate::spec::{FloatAbi, FramePointer, Target, TargetMetadata, TargetOptions, base, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv5te-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Thumb-mode Bare ARMv5TE".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs
index 4333a9c631c..3b4b94da057 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs
@@ -1,11 +1,11 @@
 // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture)
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv6m-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare ARMv6-M".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs
index dcf98acc41f..3c6133dc7ce 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs
@@ -1,11 +1,11 @@
 // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture)
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv6m-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs
index b5cb393f4b0..5660f97c8b5 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs
@@ -4,12 +4,12 @@
 // and will use software floating point operations. This matches the NuttX EABI
 // configuration without hardware floating point support.
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv7a-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs
index 1aa44a8cc93..d79970b0a0d 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs
@@ -7,12 +7,12 @@
 // This target uses the "hard" floating convention (ABI) where floating point values
 // are passed to/from subroutines via FPU registers (S0, S1, D0, D1, etc.).
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv7a-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs
index a62d03ba0d3..33da885cc1a 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs
@@ -1,4 +1,6 @@
-use crate::spec::{FloatAbi, LinkerFlavor, Lld, PanicStrategy, Target, TargetOptions, base};
+use crate::spec::{
+    FloatAbi, LinkerFlavor, Lld, PanicStrategy, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_msvc::opts();
@@ -13,7 +15,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "thumbv7a-pc-windows-msvc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs
index c9df66253b3..b4cc960939e 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs
@@ -1,9 +1,9 @@
-use crate::spec::{FloatAbi, PanicStrategy, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, PanicStrategy, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv7a-pc-windows-msvc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs
index b5cf8ce74f4..c747d721b67 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs
@@ -9,12 +9,12 @@
 // To opt-in to hardware accelerated floating point operations, you can use, for example,
 // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`.
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv7em-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare ARMv7E-M".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs
index c7b54b94efa..309d32042a0 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs
@@ -8,12 +8,12 @@
 //
 // To opt into double precision hardware support, use the `-C target-feature=+fp64` flag.
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv7em-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare ARMv7E-M, hardfloat".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs
index a3bc4013e53..57ef4e75e64 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs
@@ -9,12 +9,12 @@
 // To opt-in to hardware accelerated floating point operations, you can use, for example,
 // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`.
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv7em-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs
index 14bbe38257d..0518872dd62 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs
@@ -8,12 +8,12 @@
 //
 // To opt into double precision hardware support, use the `-C target-feature=+fp64` flag.
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv7em-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs
index 50f7bc1f810..f261009d854 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs
@@ -1,11 +1,11 @@
 // Targets the Cortex-M3 processor (ARMv7-M)
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv7m-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare ARMv7-M".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs
index 2a77f48a9cd..611795e58f1 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs
@@ -1,11 +1,11 @@
 // Targets the Cortex-M3 processor (ARMv7-M)
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv7m-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs
index de3ac26a2bd..d3a25163c53 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, FloatAbi, LinkerFlavor, Lld, Target, TargetOptions, base};
+use crate::spec::{Cc, FloatAbi, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base};
 
 // This target if is for the Android v7a ABI in thumb mode with
 // NEON unconditionally enabled and, therefore, with 32 FPU registers
@@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-march=armv7-a"]);
     Target {
         llvm_target: "armv7-none-linux-android".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Thumb2-mode ARMv7-A Android with NEON".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs
index 120f13ae56d..cce49f274ac 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 // This target is for glibc Linux on ARMv7 with thumb mode enabled
 // (for consistency with Android and Debian-based distributions)
@@ -9,7 +9,7 @@ use crate::spec::{FloatAbi, Target, TargetOptions, base};
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some(
                 "Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23)".into(),
             ),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs
index 1149b6d16eb..81c502bfead 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 // This target is for musl Linux on ARMv7 with thumb mode enabled
 // (for consistency with Android and Debian-based distributions)
@@ -9,7 +9,7 @@ use crate::spec::{FloatAbi, Target, TargetOptions, base};
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-musleabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Thumb2-mode ARMv7-A Linux with NEON, musl 1.2.3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs
index 823fb828e4d..b35f7bac93b 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs
@@ -1,11 +1,11 @@
 // Targets the Cortex-M23 processor (Baseline ARMv8-M)
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.base-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare ARMv8-M Baseline".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs
index 25a100e9c7e..4e5f6898651 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs
@@ -1,11 +1,11 @@
 // Targets the Cortex-M23 processor (Baseline ARMv8-M)
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.base-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs
index 47304e3027d..38143904efd 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs
@@ -1,12 +1,12 @@
 // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile),
 // without the Floating Point extension.
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.main-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare ARMv8-M Mainline".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs
index ddb5132ba60..55b7561da84 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs
@@ -1,12 +1,12 @@
 // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile),
 // with the Floating Point extension.
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.main-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Bare ARMv8-M Mainline, hardfloat".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs
index 0bfe2b32ad4..56aca0a8829 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs
@@ -1,12 +1,12 @@
 // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile),
 // without the Floating Point extension.
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.main-none-eabi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs
index 9f75f23aa93..47525e704da 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs
@@ -1,12 +1,12 @@
 // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile),
 // with the Floating Point extension.
 
-use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
+use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.main-none-eabihf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
index bdb1fc55711..4624c0fd5cb 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
@@ -1,5 +1,6 @@
 use crate::spec::{
-    LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions, base, cvs,
+    LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, base,
+    cvs,
 };
 
 pub(crate) fn target() -> Target {
@@ -25,7 +26,7 @@ pub(crate) fn target() -> Target {
     };
     Target {
         llvm_target: "wasm32-unknown-emscripten".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("WebAssembly via Emscripten".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs
index bcf7b69fe74..b5792731a90 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs
@@ -10,7 +10,7 @@
 //! This target is more or less managed by the Rust and WebAssembly Working
 //! Group nowadays at <https://github.com/rustwasm>.
 
-use crate::spec::{Cc, LinkerFlavor, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut options = base::wasm::options();
@@ -36,7 +36,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "wasm32-unknown-unknown".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("WebAssembly".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
index 0862958d05d..26add451ed2 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
@@ -10,7 +10,9 @@
 //! was since renamed to `wasm32-wasip1` after the preview2 target was
 //! introduced.
 
-use crate::spec::{Cc, LinkSelfContainedDefault, LinkerFlavor, Target, base, crt_objects};
+use crate::spec::{
+    Cc, LinkSelfContainedDefault, LinkerFlavor, Target, TargetMetadata, base, crt_objects,
+};
 
 pub(crate) fn target() -> Target {
     let mut options = base::wasm::options();
@@ -48,7 +50,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "wasm32-wasip1".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("WebAssembly with WASI".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
index 2411d386f52..44d906a507d 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
@@ -7,7 +7,9 @@
 //!
 //! Historically this target was known as `wasm32-wasi-preview1-threads`.
 
-use crate::spec::{Cc, LinkSelfContainedDefault, LinkerFlavor, Target, base, crt_objects};
+use crate::spec::{
+    Cc, LinkSelfContainedDefault, LinkerFlavor, Target, TargetMetadata, base, crt_objects,
+};
 
 pub(crate) fn target() -> Target {
     let mut options = base::wasm::options();
@@ -61,7 +63,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "wasm32-wasi".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
index 3f4618fad5a..7ad675dc3cf 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
@@ -16,7 +16,9 @@
 //! You can see more about wasi at <https://wasi.dev> and the component model at
 //! <https://github.com/WebAssembly/component-model>.
 
-use crate::spec::{LinkSelfContainedDefault, RelocModel, Target, base, crt_objects};
+use crate::spec::{
+    LinkSelfContainedDefault, RelocModel, Target, TargetMetadata, base, crt_objects,
+};
 
 pub(crate) fn target() -> Target {
     let mut options = base::wasm::options();
@@ -59,7 +61,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "wasm32-wasip2".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("WebAssembly".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs
index ab1dc21d125..e554e2ac076 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs
@@ -12,7 +12,7 @@
 //! nightly Rust feature `-Zbuild-std`. This target is for people who want to
 //! use stable Rust, and target a stable set pf WebAssembly features.
 
-use crate::spec::{Cc, LinkerFlavor, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut options = base::wasm::options();
@@ -43,7 +43,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "wasm32-unknown-unknown".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("WebAssembly".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs
index 596e26d1e9d..e8ac93a87ca 100644
--- a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs
@@ -7,7 +7,7 @@
 //! the standard library is available, most of it returns an error immediately
 //! (e.g. trying to create a TCP stream or something like that).
 
-use crate::spec::{Cc, LinkerFlavor, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut options = base::wasm::options();
@@ -39,7 +39,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "wasm64-unknown-unknown".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("WebAssembly".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
index 52ef3fc88fd..2f868e38f1a 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("macos", Arch::X86_64, TargetAbi::Normal);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("x86_64 Apple macOS (10.12+, Sierra+)".into()),
             tier: Some(1),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs
index f421e6b8984..df45f430ecb 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs
@@ -1,5 +1,5 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{SanitizerSet, Target, TargetOptions};
+use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     // x86_64-apple-ios is a simulator target, even though it isn't declared
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetAbi::Simulator);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("x86_64 Apple iOS Simulator".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs
index 3687446b939..ee0c2bf31cd 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{SanitizerSet, Target, TargetOptions};
+use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetAbi::MacCatalyst);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("x86_64 Apple Mac Catalyst".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs
index 07338a364e8..80ca80013f0 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs
@@ -1,5 +1,5 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     // x86_64-apple-tvos is a simulator target, even though it isn't declared
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("tvos", Arch::X86_64, TargetAbi::Simulator);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("x86_64 Apple tvOS Simulator".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs
index 4a03c250e6f..c503baedb8b 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs
@@ -1,11 +1,11 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (opts, llvm_target, arch) = base("watchos", Arch::X86_64, TargetAbi::Simulator);
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("x86_64 Apple watchOS Simulator".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs
index 60d078371bb..bbaee6c1f6d 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs
@@ -1,6 +1,6 @@
 use std::borrow::Cow;
 
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions, cvs};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, cvs};
 
 pub(crate) fn target() -> Target {
     let pre_link_args = TargetOptions::link_args(
@@ -74,7 +74,7 @@ pub(crate) fn target() -> Target {
     };
     Target {
         llvm_target: "x86_64-elf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Fortanix ABI for 64-bit Intel SGX".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs
index d8f74f66f70..3a0acaa028c 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs
@@ -1,5 +1,6 @@
 use crate::spec::{
-    Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetOptions, base,
+    Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions,
+    base,
 };
 
 pub(crate) fn target() -> Target {
@@ -15,7 +16,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-linux-android".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit x86 Android".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs
index 843568a4792..662bbc4a31c 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, SanitizerSet, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::solaris::opts();
@@ -12,7 +12,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-solaris".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit Solaris 11.4".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
index b10d4478d5e..16bdd3ee668 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_gnu::opts();
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-windows-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit MinGW (Windows 10+)".into()),
             tier: Some(1),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
index 46c233f1863..1a03390c2b8 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_gnullvm::opts();
@@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-windows-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit x86 MinGW (Windows 10+), LLVM ABI".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
index baf0d8b0c8b..d88aabaa6d3 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{SanitizerSet, Target, base};
+use crate::spec::{SanitizerSet, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_msvc::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-windows-msvc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit MSVC (Windows 10+)".into()),
             tier: Some(1),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs
index 8aa0128aaa3..a5723341fe6 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs
@@ -1,9 +1,11 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit Unikraft with musl 1.2.3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs
index 6492d3d7d2f..715c0db632b 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::dragonfly::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-dragonfly".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit DragonFlyBSD".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs
index 62cafd502e4..4a074539aab 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetMetadata, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::freebsd::opts();
@@ -13,7 +15,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-freebsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit FreeBSD".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs
index a45f8159de0..d41c696ac23 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs
@@ -1,4 +1,4 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target, base};
+use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::fuchsia::opts();
@@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-fuchsia".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit x86 Fuchsia".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs
index b70b38dbbfe..ecb9fc80351 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::haiku::opts();
@@ -12,7 +12,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-haiku".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit Haiku".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs
index 2e239cafe95..7abde771798 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs
@@ -1,9 +1,9 @@
-use crate::spec::{StackProbeType, Target, TargetOptions, base};
+use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-hermit".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("x86_64 Hermit".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hurd_gnu.rs
index 34835a20956..57ce67af36d 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hurd_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hurd_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::hurd_gnu::opts();
@@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-hurd-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit GNU/Hurd".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs
index 69715fc257f..17f90db0c90 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, SanitizerSet, Target, base};
+use crate::spec::{Cc, LinkerFlavor, SanitizerSet, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::illumos::opts();
@@ -12,7 +12,7 @@ pub(crate) fn target() -> Target {
         // LLVM does not currently have a separate illumos target,
         // so we still pass Solaris to it
         llvm_target: "x86_64-pc-solaris".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("illumos".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs
index db7e402cc80..a034a9fb244 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{PanicStrategy, Target, base};
+use crate::spec::{PanicStrategy, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::l4re::opts();
@@ -9,7 +9,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-l4re-uclibc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
index 59ec6c7f9d5..0c8353fad18 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetMetadata, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -27,7 +29,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit Linux (kernel 3.2+, glibc 2.17+)".into()),
             tier: Some(1),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs
index 8a613477940..c5d556e5cc6 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -14,7 +14,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-linux-gnux32".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs
index 8dcdc5be8a9..cc5f8886240 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetMetadata, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -19,7 +21,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-linux-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit Linux with musl 1.2.3".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs
index 2e63ff21572..896e8a78f86 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, StackProbeType, Target, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, StackProbeType, Target, TargetMetadata, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux::opts();
@@ -11,7 +13,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-linux-none".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: None,
             host_tools: None,
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs
index 522943c91a5..de9027ba962 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, base};
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetMetadata, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_ohos::opts();
@@ -16,7 +18,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-linux-ohos".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("x86_64 OpenHarmony".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs
index e4972941957..0403c220982 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs
@@ -1,5 +1,6 @@
 use crate::spec::{
-    Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetOptions, base,
+    Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions,
+    base,
 };
 
 pub(crate) fn target() -> Target {
@@ -18,7 +19,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-netbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("NetBSD/amd64".into()),
             tier: Some(2),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs
index e14a3673589..1a6343595f5 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs
@@ -6,7 +6,7 @@
 
 use crate::spec::{
     Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelroLevel, RustcAbi, SanitizerSet,
-    StackProbeType, Target, TargetOptions,
+    StackProbeType, Target, TargetMetadata, TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
@@ -30,7 +30,7 @@ pub(crate) fn target() -> Target {
     };
     Target {
         llvm_target: "x86_64-unknown-none-elf".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Freestanding/bare-metal x86_64 softfloat".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs
index 3135ecf45dc..2eb09b8cbad 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::openbsd::opts();
@@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-openbsd".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit OpenBSD".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs
index 43a28fca09a..65b8e2543a4 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::redox::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-redox".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Redox OS".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs
index a6af06b03db..c7b002bc9bb 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs
@@ -1,13 +1,14 @@
 // Trusty OS target for X86_64.
 
 use crate::spec::{
-    LinkSelfContainedDefault, PanicStrategy, RelroLevel, StackProbeType, Target, TargetOptions,
+    LinkSelfContainedDefault, PanicStrategy, RelroLevel, StackProbeType, Target, TargetMetadata,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-unknown-musl".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("x86_64 Trusty".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs
index bce6aa0ebc6..07f853dacaf 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs
@@ -6,7 +6,7 @@
 // LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
 
 use crate::callconv::Conv;
-use crate::spec::{RustcAbi, Target, base};
+use crate::spec::{RustcAbi, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::uefi_msvc::opts();
@@ -30,7 +30,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-windows".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit UEFI".into()),
             tier: Some(2),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
index 0ef41d315af..bf6179cb6c3 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_uwp_gnu::opts();
@@ -15,7 +15,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-windows-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
index 31861c16099..50b0578da35 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Target, base};
+use crate::spec::{Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_uwp_msvc::opts();
@@ -9,7 +9,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-windows-msvc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs
index 8f903934a90..df1fe8e7853 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_gnu::opts();
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-windows-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit MinGW (Windows 7+)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
index 2eceb688108..876ac011879 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{SanitizerSet, Target, base};
+use crate::spec::{SanitizerSet, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_msvc::opts();
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-windows-msvc".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("64-bit MSVC (Windows 7+)".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs
index f003f939ad1..9ab62b3530f 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, base};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::vxworks::opts();
@@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-linux-gnu".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: None,
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs
index 0f73a860821..11010b7d92f 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs
@@ -1,5 +1,5 @@
 use crate::spec::base::apple::{Arch, TargetAbi, base};
-use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     let (mut opts, llvm_target, arch) = base("macos", Arch::X86_64h, TargetAbi::Normal);
@@ -28,7 +28,7 @@ pub(crate) fn target() -> Target {
 
     Target {
         llvm_target,
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("x86_64 Apple macOS with Intel Haswell+".into()),
             tier: Some(3),
             host_tools: Some(true),
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs
index b2a7c8551e4..c5b4d472fad 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs
@@ -1,7 +1,7 @@
 use rustc_abi::Endian;
 
 use crate::spec::base::xtensa;
-use crate::spec::{Target, TargetOptions, cvs};
+use crate::spec::{Target, TargetMetadata, TargetOptions, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
@@ -9,12 +9,7 @@ pub(crate) fn target() -> Target {
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
         arch: "xtensa".into(),
-        metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
-        },
+        metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None },
 
         options: TargetOptions {
             endian: Endian::Little,
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs
index 254ae54db21..d8638e8ac80 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs
@@ -1,5 +1,5 @@
 use crate::spec::base::xtensa;
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     Target {
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
         arch: "xtensa".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Xtensa ESP32".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
index 4fab2bac8e2..dd98f34d323 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
@@ -1,7 +1,7 @@
 use rustc_abi::Endian;
 
 use crate::spec::base::xtensa;
-use crate::spec::{Target, TargetOptions, cvs};
+use crate::spec::{Target, TargetMetadata, TargetOptions, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
@@ -9,12 +9,7 @@ pub(crate) fn target() -> Target {
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
         arch: "xtensa".into(),
-        metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
-        },
+        metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None },
 
         options: TargetOptions {
             endian: Endian::Little,
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
index ae7bfbd0394..29bcf12cbaf 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
@@ -1,5 +1,5 @@
 use crate::spec::base::xtensa;
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     Target {
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
         arch: "xtensa".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Xtensa ESP32-S2".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
index 45d409a509f..dd6e7b6c3e8 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
@@ -1,7 +1,7 @@
 use rustc_abi::Endian;
 
 use crate::spec::base::xtensa;
-use crate::spec::{Target, TargetOptions, cvs};
+use crate::spec::{Target, TargetMetadata, TargetOptions, cvs};
 
 pub(crate) fn target() -> Target {
     Target {
@@ -9,12 +9,7 @@ pub(crate) fn target() -> Target {
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
         arch: "xtensa".into(),
-        metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
-        },
+        metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None },
 
         options: TargetOptions {
             endian: Endian::Little,
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
index 023a67f2871..ddc909f387e 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
@@ -1,5 +1,5 @@
 use crate::spec::base::xtensa;
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Target, TargetMetadata, TargetOptions};
 
 pub(crate) fn target() -> Target {
     Target {
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
         arch: "xtensa".into(),
-        metadata: crate::spec::TargetMetadata {
+        metadata: TargetMetadata {
             description: Some("Xtensa ESP32-S3".into()),
             tier: Some(3),
             host_tools: Some(false),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 091773009e9..a618bae269f 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -1989,7 +1989,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         trace: &TypeTrace<'tcx>,
         span: Span,
     ) -> Option<TypeErrorAdditionalDiags> {
-        let hir = self.tcx.hir();
         let TypeError::ArraySize(sz) = terr else {
             return None;
         };
@@ -1997,7 +1996,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             hir::Node::Item(hir::Item {
                 kind: hir::ItemKind::Fn { body: body_id, .. }, ..
             }) => {
-                let body = hir.body(*body_id);
+                let body = self.tcx.hir_body(*body_id);
                 struct LetVisitor {
                     span: Span,
                 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index 9e7e96dddd7..2bb38f3ed14 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -489,7 +489,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         };
 
         let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, arg);
-        if let Some(body) = self.tcx.hir().maybe_body_owned_by(
+        if let Some(body) = self.tcx.hir_maybe_body_owned_by(
             self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(),
         ) {
             let expr = body.value;
@@ -1202,8 +1202,8 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tecx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tecx.tcx
     }
 
     fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) {
@@ -1320,7 +1320,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
             {
                 let output = args.as_closure().sig().output().skip_binder();
                 if self.generic_arg_contains_target(output.into()) {
-                    let body = self.tecx.tcx.hir().body(body);
+                    let body = self.tecx.tcx.hir_body(body);
                     let should_wrap_expr = if matches!(body.value.kind, ExprKind::Block(..)) {
                         None
                     } else {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
index b9f3abc2534..5a303c3cd03 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
@@ -3,7 +3,6 @@ use core::ops::ControlFlow;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor, VisitorExt};
 use rustc_hir::{self as hir, AmbigArg};
-use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars as rbv;
 use rustc_middle::ty::{self, Region, TyCtxt};
@@ -70,8 +69,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
     type Result = ControlFlow<&'tcx hir::Ty<'tcx>>;
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
@@ -176,8 +175,8 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
     type Result = ControlFlow<()>;
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Map<'tcx> {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) -> Self::Result {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
index 886581bc35f..ad2f7f00fa5 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
@@ -66,7 +66,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         );
         let mut impl_span = None;
         let mut implicit_static_lifetimes = Vec::new();
-        if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
+        if let Some(impl_node) = self.tcx().hir_get_if_local(*impl_def_id) {
             // If an impl is local, then maybe this isn't what they want. Try to
             // be as helpful as possible with implicit lifetimes.
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index 039e21cb556..5b8d48e3ca9 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
@@ -147,7 +147,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             | ObligationCauseCode::BlockTailExpression(hir_id, ..) = cause.code()
             {
                 let parent_id = tcx.hir().get_parent_item(*hir_id);
-                if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
+                if let Some(fn_decl) = tcx.hir_fn_decl_by_hir_id(parent_id.into()) {
                     let mut span: MultiSpan = fn_decl.output.span().into();
                     let mut spans = Vec::new();
                     let mut add_label = true;
@@ -318,7 +318,7 @@ pub fn suggest_new_region_bound(
                 } else {
                     // get a lifetime name of existing named lifetimes if any
                     let existing_lt_name = if let Some(id) = scope_def_id
-                        && let Some(generics) = tcx.hir().get_generics(id)
+                        && let Some(generics) = tcx.hir_get_generics(id)
                         && let named_lifetimes = generics
                             .params
                             .iter()
@@ -349,7 +349,7 @@ pub fn suggest_new_region_bound(
                     // if there are more than one elided lifetimes in inputs, the explicit `'_` lifetime cannot be used.
                     // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any
                     if let Some(id) = scope_def_id
-                        && let Some(generics) = tcx.hir().get_generics(id)
+                        && let Some(generics) = tcx.hir_get_generics(id)
                         && let mut spans_suggs =
                             make_elided_region_spans_suggs(name, generics.params.iter())
                         && spans_suggs.len() > 1
@@ -470,7 +470,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         def_id: DefId,
         trait_objects: &FxIndexSet<DefId>,
     ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
-        match tcx.hir().get_if_local(def_id)? {
+        match tcx.hir_get_if_local(def_id)? {
             Node::ImplItem(impl_item) => {
                 let impl_did = tcx.hir().get_parent_item(impl_item.hir_id());
                 if let hir::OwnerNode::Item(Item {
@@ -490,7 +490,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 // obligation comes from the `impl`. Find that `impl` so that we can point
                 // at it in the suggestion.
                 let trait_did = trait_id.to_def_id();
-                tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
+                tcx.hir_trait_impls(trait_did).iter().find_map(|&impl_did| {
                     if let Node::Item(Item {
                         kind: ItemKind::Impl(hir::Impl { self_ty, .. }), ..
                     }) = tcx.hir_node_by_def_id(impl_did)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
index bbcd28c0835..cc2ab1c3432 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
@@ -99,11 +99,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
         match assoc_item.kind {
             ty::AssocKind::Fn => {
-                let hir = self.tcx().hir();
                 if let Some(hir_id) =
                     assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id))
                 {
-                    if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) {
+                    if let Some(decl) = self.tcx().hir_fn_decl_by_hir_id(hir_id) {
                         visitor.visit_fn_decl(decl);
                     }
                 }
@@ -133,8 +132,8 @@ struct TypeParamSpanVisitor<'tcx> {
 impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs
index 445937ad169..245764c94ab 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs
@@ -64,10 +64,10 @@ pub fn find_param_with_region<'tcx>(
         _ => {}
     }
 
-    let body = hir.maybe_body_owned_by(def_id)?;
+    let body = tcx.hir_maybe_body_owned_by(def_id)?;
 
-    let owner_id = hir.body_owner(body.id());
-    let fn_decl = hir.fn_decl_by_hir_id(owner_id)?;
+    let owner_id = tcx.hir_body_owner(body.id());
+    let fn_decl = tcx.hir_fn_decl_by_hir_id(owner_id)?;
     let poly_fn_sig = tcx.fn_sig(id).instantiate_identity();
 
     let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig);
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index e8d14b89d69..37032b53901 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -543,7 +543,7 @@ impl<T> Trait<T> for X {
         let tcx = self.tcx;
         let assoc = tcx.associated_item(proj_ty.def_id);
         let (trait_ref, assoc_args) = proj_ty.trait_ref_and_own_args(tcx);
-        let Some(item) = tcx.hir().get_if_local(body_owner_def_id) else {
+        let Some(item) = tcx.hir_get_if_local(body_owner_def_id) else {
             return false;
         };
         let Some(hir_generics) = item.generics() else {
@@ -625,7 +625,7 @@ impl<T> Trait<T> for X {
             )
         };
 
-        let body_owner = tcx.hir().get_if_local(body_owner_def_id);
+        let body_owner = tcx.hir_get_if_local(body_owner_def_id);
         let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
 
         // We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index f35a5349ecb..fecb38ab597 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -2,7 +2,7 @@ use std::iter;
 
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
-    Applicability, Diag, E0309, E0310, E0311, E0495, Subdiagnostic, struct_span_code_err,
+    Applicability, Diag, E0309, E0310, E0311, E0803, Subdiagnostic, struct_span_code_err,
 };
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -487,7 +487,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     &format!("`{sup}: {sub}`"),
                 );
                 // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
-                if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
+                if let Some(generics) = self.tcx.hir_get_generics(impl_item_def_id)
                     && generics.where_clause_span.contains(span)
                 {
                     self.suggest_copy_trait_method_bounds(
@@ -590,7 +590,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             return;
         };
 
-        let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else {
+        let Some(generics) = self.tcx.hir_get_generics(impl_item_def_id) else {
             return;
         };
 
@@ -763,7 +763,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     // Get the `hir::Param` to verify whether it already has any bounds.
                     // We do this to avoid suggesting code that ends up as `T: 'a'b`,
                     // instead we suggest `T: 'a + 'b` in that case.
-                    let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
+                    let hir_generics = self.tcx.hir_get_generics(scope).unwrap();
                     let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
                         Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)),
                         // If `param` corresponds to `Self`, no usable suggestion span.
@@ -822,7 +822,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             {
                 // The lifetime found in the `impl` is longer than the one on the RPITIT.
                 // Do not suggest `<Type as Trait>::{opaque}: 'static`.
-            } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) {
+            } else if let Some(generics) = self.tcx.hir_get_generics(suggestion_scope) {
                 let pred = format!("{bound_kind}: {lt_name}");
                 let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
                 suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion))
@@ -907,7 +907,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             hir::OwnerNode::Synthetic => unreachable!(),
         }
 
-        let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap();
+        let ast_generics = self.tcx.hir_get_generics(lifetime_scope).unwrap();
         let sugg = ast_generics
             .span_for_lifetime_suggestion()
             .map(|span| (span, format!("{new_lt}, ")))
@@ -1032,7 +1032,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         struct_span_code_err!(
             self.dcx(),
             var_origin.span(),
-            E0495,
+            E0803,
             "cannot infer an appropriate lifetime{} due to conflicting requirements",
             var_description
         )
@@ -1382,7 +1382,7 @@ fn suggest_precise_capturing<'tcx>(
                 new_params += name_as_bounds;
             }
 
-            let Some(generics) = tcx.hir().get_generics(fn_def_id) else {
+            let Some(generics) = tcx.hir_get_generics(fn_def_id) else {
                 // This shouldn't happen, but don't ICE.
                 return;
             };
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index 562000e28ac..628888c8d45 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -624,7 +624,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
         }
 
-        self.tcx.hir().maybe_body_owned_by(cause.body_id).and_then(|body| {
+        self.tcx.hir_maybe_body_owned_by(cause.body_id).and_then(|body| {
             IfVisitor { err_span: span, found_if: false }
                 .visit_body(&body)
                 .is_break()
@@ -649,7 +649,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         else {
             return;
         };
-        let hir::Body { params, .. } = self.tcx.hir().body(*body);
+        let hir::Body { params, .. } = self.tcx.hir_body(*body);
 
         // 1. Get the args of the closure.
         // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1].
@@ -846,7 +846,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             true
         };
 
-        let hir = self.tcx.hir();
         for stmt in blk.stmts.iter().rev() {
             let hir::StmtKind::Let(local) = &stmt.kind else {
                 continue;
@@ -871,7 +870,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
                     ..
                 }) => {
-                    for param in hir.body(*body).params {
+                    for param in self.tcx.hir_body(*body).params {
                         param.pat.walk(&mut find_compatible_candidates);
                     }
                 }
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 6beb108bc3a..f15f1b78b52 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -316,7 +316,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
 
                 if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack())
-                    && let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
+                    && let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id)
                 {
                     let mut expr_finder = FindExprBySpan::new(span, self.tcx);
                     expr_finder.visit_expr(&body.value);
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 49fa21e50c0..a8ee4d61e65 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -367,7 +367,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                         (span.shrink_to_lo(), format!("(")),
                                         (span.shrink_to_hi(), format!(" as {})", cand.self_ty())),
                                     ]
-                                } else if let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) {
+                                } else if let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) {
                                     let mut expr_finder = FindExprBySpan::new(span, self.tcx);
                                     expr_finder.visit_expr(body.value);
                                     if let Some(expr) = expr_finder.result &&
@@ -925,7 +925,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id);
         let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return false };
         let ControlFlow::Break(expr) =
-            (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir().body(body_id))
+            (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir_body(body_id))
         else {
             return false;
         };
@@ -1012,7 +1012,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 && let [arg] = args
                 && let hir::ExprKind::Closure(closure) = arg.kind
                 // The closure has a block for its body with no tail expression
-                && let body = self.tcx.hir().body(closure.body)
+                && let body = self.tcx.hir_body(closure.body)
                 && let hir::ExprKind::Block(block, _) = body.value.kind
                 && let None = block.expr
                 // The last statement is of a type that can be converted to the return error type
@@ -1447,7 +1447,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 let [associated_item]: &[ty::AssocItem] = &associated_items[..] else {
                     return None;
                 };
-                match self.tcx.hir().get_if_local(associated_item.def_id) {
+                match self.tcx.hir_get_if_local(associated_item.def_id) {
                     Some(
                         hir::Node::TraitItem(hir::TraitItem {
                             kind: hir::TraitItemKind::Type(_, Some(ty)),
@@ -1514,7 +1514,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         span = match fn_decl.output {
                             hir::FnRetTy::Return(ty) => ty.span,
                             hir::FnRetTy::DefaultReturn(_) => {
-                                let body = self.tcx.hir().body(id);
+                                let body = self.tcx.hir_body(id);
                                 match body.value.kind {
                                     hir::ExprKind::Block(
                                         hir::Block { expr: Some(expr), .. },
@@ -2850,7 +2850,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             _ => None,
         };
 
-        let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
+        let found_node = found_did.and_then(|did| self.tcx.hir_get_if_local(did));
         let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
 
         if !self.reported_signature_mismatch.borrow_mut().insert((span, found_span)) {
@@ -2896,7 +2896,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         if found.len() != expected.len() {
             let (closure_span, closure_arg_span, found) = found_did
                 .and_then(|did| {
-                    let node = self.tcx.hir().get_if_local(did)?;
+                    let node = self.tcx.hir_get_if_local(did)?;
                     let (found_span, closure_arg_span, found) = self.get_fn_like_arguments(node)?;
                     Some((Some(found_span), closure_arg_span, found))
                 })
@@ -2946,7 +2946,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }) => (
                 fn_decl_span,
                 fn_arg_span,
-                hir.body(body)
+                self.tcx
+                    .hir_body(body)
                     .params
                     .iter()
                     .map(|arg| {
@@ -3208,7 +3209,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                 Some(obligation.cause.body_id)
                             };
                             if let Some(def_id) = def_id
-                                && let Some(generics) = self.tcx.hir().get_generics(def_id)
+                                && let Some(generics) = self.tcx.hir_get_generics(def_id)
                             {
                                 err.span_suggestion_verbose(
                                     generics.tail_span_for_predicate_suggestion(),
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 e4f250ca4f5..22d219cd64d 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -68,8 +68,8 @@ impl<'hir> FindExprBySpan<'hir> {
 impl<'v> Visitor<'v> for FindExprBySpan<'v> {
     type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
@@ -418,7 +418,7 @@ pub fn report_dyn_incompatibility<'tcx>(
     violations: &[DynCompatibilityViolation],
 ) -> Diag<'tcx> {
     let trait_str = tcx.def_path_str(trait_def_id);
-    let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node {
+    let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
         hir::Node::Item(item) => Some(item.ident.span),
         _ => None,
     });
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 527d2e54e43..3d89b6ed2f0 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -790,8 +790,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
 
         // Get the name of the callable and the arguments to be used in the suggestion.
-        let hir = self.tcx.hir();
-
         let msg = match def_id_or_name {
             DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
                 DefKind::Ctor(CtorOf::Struct, _) => {
@@ -834,7 +832,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 Applicability::HasPlaceholders,
             );
         } else if let DefIdOrName::DefId(def_id) = def_id_or_name {
-            let name = match hir.get_if_local(def_id) {
+            let name = match self.tcx.hir_get_if_local(def_id) {
                 Some(hir::Node::Expr(hir::Expr {
                     kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),
                     ..
@@ -878,7 +876,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             span.remove_mark();
         }
         let mut expr_finder = FindExprBySpan::new(span, self.tcx);
-        let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else {
+        let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {
             return;
         };
         expr_finder.visit_expr(body.value);
@@ -950,7 +948,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     ) -> bool {
         let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
         self.enter_forall(self_ty, |ty: Ty<'_>| {
-            let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else {
+            let Some(generics) = self.tcx.hir_get_generics(obligation.cause.body_id) else {
                 return false;
             };
             let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };
@@ -1349,8 +1347,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         // Issue #104961, we need to add parentheses properly for compound expressions
                         // for example, `x.starts_with("hi".to_string() + "you")`
                         // should be `x.starts_with(&("hi".to_string() + "you"))`
-                        let Some(body) =
-                            self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
+                        let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id)
                         else {
                             return false;
                         };
@@ -1449,7 +1446,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             span.remove_mark();
         }
         let mut expr_finder = super::FindExprBySpan::new(span, self.tcx);
-        let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else {
+        let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {
             return false;
         };
         expr_finder.visit_expr(body.value);
@@ -1595,7 +1592,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     && let ty = typeck_results.expr_ty_adjusted(base)
                     && let ty::FnDef(def_id, _args) = ty.kind()
                     && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
-                        hir.get_if_local(*def_id)
+                        self.tcx.hir_get_if_local(*def_id)
                 {
                     let msg = format!("alternatively, consider making `fn {ident}` asynchronous");
                     if vis_span.is_empty() {
@@ -1703,10 +1700,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         span: Span,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
-        let hir = self.tcx.hir();
         let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
         if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn {sig, body: body_id, .. }, .. }) = node
-            && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind
+            && let hir::ExprKind::Block(blk, _) = &self.tcx.hir_body(*body_id).value.kind
             && sig.decl.output.span().overlaps(span)
             && blk.expr.is_none()
             && trait_pred.self_ty().skip_binder().is_unit()
@@ -1769,7 +1765,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         err.children.clear();
 
         let span = obligation.cause.span;
-        let body = self.tcx.hir().body_owned_by(obligation.cause.body_id);
+        let body = self.tcx.hir_body_owned_by(obligation.cause.body_id);
 
         let mut visitor = ReturnsVisitor::default();
         visitor.visit_body(&body);
@@ -2303,7 +2299,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         );
 
         let coroutine_body =
-            coroutine_did.as_local().and_then(|def_id| hir.maybe_body_owned_by(def_id));
+            coroutine_did.as_local().and_then(|def_id| self.tcx.hir_maybe_body_owned_by(def_id));
         let mut visitor = AwaitsVisitor::default();
         if let Some(body) = coroutine_body {
             visitor.visit_body(&body);
@@ -2790,7 +2786,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                     generics,
                                     kind: hir::TraitItemKind::Type(bounds, None),
                                     ..
-                                })) = tcx.hir().get_if_local(item_def_id)
+                                })) = tcx.hir_get_if_local(item_def_id)
                                     // Do not suggest relaxing if there is an explicit `Sized` obligation.
                                     && !bounds.iter()
                                         .filter_map(|bound| bound.trait_ref())
@@ -3298,7 +3294,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string();
                 let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
                 let mut is_auto_trait = false;
-                match tcx.hir().get_if_local(data.impl_or_alias_def_id) {
+                match tcx.hir_get_if_local(data.impl_or_alias_def_id) {
                     Some(Node::Item(hir::Item {
                         kind: hir::ItemKind::Trait(is_auto, ..),
                         ident,
@@ -3423,7 +3419,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         .map_bound(|pred| pred.trait_ref)
                         .print_only_trait_path(),
                 );
-                match tcx.hir().get_if_local(data.impl_def_id) {
+                match tcx.hir_get_if_local(data.impl_def_id) {
                     Some(Node::Item(hir::Item {
                         kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
                         ..
@@ -3564,7 +3560,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     let expr = tcx.hir().expect_expr(hir_id);
                     (expr_ty, expr)
                 } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id()
-                    && let body = tcx.hir().body(body_id)
+                    && let body = tcx.hir_body(body_id)
                     && let hir::ExprKind::Block(block, _) = body.value.kind
                     && let Some(expr) = block.expr
                     && let Some(expr_ty) = self
@@ -3841,7 +3837,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             && let hir::ExprKind::Closure(hir::Closure {
                                 body, fn_decl_span, ..
                             }) = value.kind
-                            && let body = tcx.hir().body(*body)
+                            && let body = tcx.hir_body(*body)
                             && !matches!(body.value.kind, hir::ExprKind::Block(..))
                         {
                             // Check if the failed predicate was an expectation of a closure type
@@ -4068,7 +4064,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     && let [arg] = args
                     && let hir::ExprKind::Closure(closure) = arg.kind
                 {
-                    let body = tcx.hir().body(closure.body);
+                    let body = tcx.hir_body(closure.body);
                     if let hir::ExprKind::Block(block, None) = body.value.kind
                         && let None = block.expr
                         && let [.., stmt] = block.stmts
@@ -4133,7 +4129,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         };
                         suggest_restriction(
                             tcx,
-                            hir.body_owner_def_id(body_id),
+                            tcx.hir_body_owner_def_id(body_id),
                             generics,
                             &format!("type parameter `{ty}`"),
                             err,
@@ -4355,7 +4351,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     term: ty.into(),
                 }),
             ));
-            let body_def_id = self.tcx.hir().enclosing_body_owner(body_id);
+            let body_def_id = self.tcx.hir_enclosing_body_owner(body_id);
             // Add `<ExprTy as Iterator>::Item = _` obligation.
             ocx.register_obligation(Obligation::misc(
                 self.tcx,
@@ -4761,7 +4757,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         {
             let mut sugg_spans =
                 vec![(ret_span, " -> Result<(), Box<dyn std::error::Error>>".to_string())];
-            let body = self.tcx.hir().body(body_id);
+            let body = self.tcx.hir_body(body_id);
             if let hir::ExprKind::Block(b, _) = body.value.kind
                 && b.expr.is_none()
             {
@@ -4807,7 +4803,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         debug!(?pred, ?item_def_id, ?span);
 
         let (Some(node), true) = (
-            self.tcx.hir().get_if_local(item_def_id),
+            self.tcx.hir_get_if_local(item_def_id),
             self.tcx.is_lang_item(pred.def_id(), LangItem::Sized),
         ) else {
             return;
@@ -5248,7 +5244,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
 
     // If there's a body, we also need to wrap it in `async {}`
     if let hir::TraitFn::Provided(body) = body {
-        let body = tcx.hir().body(body);
+        let body = tcx.hir_body(body);
         let body_span = body.value.span;
         let body_span_without_braces =
             body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1));
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 62cac5b17bd..ac4399750f5 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1857,7 +1857,7 @@ pub fn impl_trait_overcapture_suggestion<'tcx>(
             new_params += name_as_bounds;
         }
 
-        let Some(generics) = tcx.hir().get_generics(fn_def_id) else {
+        let Some(generics) = tcx.hir_get_generics(fn_def_id) else {
             // This shouldn't happen, but don't ICE.
             return None;
         };
diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
index b752dbf3093..4601ddf678a 100644
--- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
@@ -26,7 +26,7 @@ impl<'a> DescriptionCtx<'a> {
                     .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id)
                     .expect_local();
                 let span = if let Some(param) =
-                    tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
+                    tcx.hir_get_generics(scope).and_then(|generics| generics.get_named(br.name))
                 {
                     param.span
                 } else {
@@ -48,8 +48,7 @@ impl<'a> DescriptionCtx<'a> {
                     match fr.kind {
                         ty::LateParamRegionKind::Named(_, name) => {
                             let span = if let Some(param) = tcx
-                                .hir()
-                                .get_generics(scope)
+                                .hir_get_generics(scope)
                                 .and_then(|generics| generics.get_named(name))
                             {
                                 param.span
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index a0df74835bc..efe2386d014 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -128,8 +128,7 @@ fn sized_trait_bound_spans<'tcx>(
 }
 
 fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
-    tcx.hir()
-        .get_if_local(trait_def_id)
+    tcx.hir_get_if_local(trait_def_id)
         .and_then(|node| match node {
             hir::Node::Item(hir::Item {
                 kind: hir::ItemKind::Trait(.., generics, bounds, _),
@@ -304,7 +303,7 @@ pub fn dyn_compatibility_violations_for_assoc_item(
         ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item)
             .into_iter()
             .map(|v| {
-                let node = tcx.hir().get_if_local(item.def_id);
+                let node = tcx.hir_get_if_local(item.def_id);
                 // Get an accurate span depending on the violation.
                 let span = match (&v, node) {
                     (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
@@ -349,7 +348,7 @@ fn virtual_call_violations_for_method<'tcx>(
             generics,
             kind: hir::TraitItemKind::Fn(sig, _),
             ..
-        })) = tcx.hir().get_if_local(method.def_id).as_ref()
+        })) = tcx.hir_get_if_local(method.def_id).as_ref()
         {
             let sm = tcx.sess.source_map();
             Some((
@@ -383,7 +382,7 @@ fn virtual_call_violations_for_method<'tcx>(
             let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
                 kind: hir::TraitItemKind::Fn(sig, _),
                 ..
-            })) = tcx.hir().get_if_local(method.def_id).as_ref()
+            })) = tcx.hir_get_if_local(method.def_id).as_ref()
             {
                 Some(sig.decl.inputs[i].span)
             } else {
@@ -421,7 +420,7 @@ fn virtual_call_violations_for_method<'tcx>(
             let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
                 kind: hir::TraitItemKind::Fn(sig, _),
                 ..
-            })) = tcx.hir().get_if_local(method.def_id).as_ref()
+            })) = tcx.hir_get_if_local(method.def_id).as_ref()
             {
                 Some(sig.decl.inputs[0].span)
             } else {
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 79e178150de..a4b6f330b9d 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -208,7 +208,7 @@ pub fn all_fields_implement_trait<'tcx>(
             }
 
             let field_span = tcx.def_span(field.did);
-            let field_ty_span = match tcx.hir().get_if_local(field.did) {
+            let field_ty_span = match tcx.hir_get_if_local(field.did) {
                 Some(hir::Node::Field(field_def)) => field_def.ty.span,
                 _ => field_span,
             };
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 2f72b44f6b6..7f3e3ce4781 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -289,7 +289,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
             && let Some(impl_item) =
                 items.iter().find(|item| item.id.owner_id.to_def_id() == impl_item_id)
         {
-            Some(tcx.hir().impl_item(impl_item.id).expect_type().span)
+            Some(tcx.hir_impl_item(impl_item.id).expect_type().span)
         } else {
             None
         }
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index 40356e0c978..f88f8c38d50 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -11,6 +11,7 @@ rustc_ast_ir = { path = "../rustc_ast_ir" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
+rustc_hashes = { path = "../rustc_hashes" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_infer = { path = "../rustc_infer" }
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index ee271048fc1..556512e0236 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -9,6 +9,7 @@ use rustc_abi::{
     HasDataLayout, Layout, LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size,
     StructKind, TagEncoding, VariantIdx, Variants, WrappingRange,
 };
+use rustc_hashes::Hash64;
 use rustc_index::bit_set::DenseBitSet;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::bug;
@@ -133,42 +134,32 @@ fn univariant_uninterned<'tcx>(
     cx: &LayoutCx<'tcx>,
     ty: Ty<'tcx>,
     fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>,
-    repr: &ReprOptions,
     kind: StructKind,
 ) -> Result<LayoutData<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
-    let pack = repr.pack;
-    if pack.is_some() && repr.align.is_some() {
-        cx.tcx().dcx().bug("struct cannot be packed and aligned");
-    }
-
-    cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err))
+    let repr = ReprOptions::default();
+    cx.calc.univariant(fields, &repr, kind).map_err(|err| map_error(cx, ty, err))
 }
 
 fn extract_const_value<'tcx>(
-    const_: ty::Const<'tcx>,
-    ty: Ty<'tcx>,
     cx: &LayoutCx<'tcx>,
+    ty: Ty<'tcx>,
+    ct: ty::Const<'tcx>,
 ) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
-    match const_.kind() {
+    match ct.kind() {
         ty::ConstKind::Value(cv) => Ok(cv),
-        ty::ConstKind::Error(guar) => {
-            return Err(error(cx, LayoutError::ReferencesError(guar)));
-        }
-        ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
-            if !const_.has_param() {
-                bug!("no generic type found in the type: {ty:?}");
-            }
-            return Err(error(cx, LayoutError::TooGeneric(ty)));
-        }
-        ty::ConstKind::Unevaluated(_) => {
-            if !const_.has_param() {
-                return Err(error(cx, LayoutError::Unknown(ty)));
-            } else {
-                return Err(error(cx, LayoutError::TooGeneric(ty)));
+        ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) => {
+            if !ct.has_param() {
+                bug!("failed to normalize const, but it is not generic: {ct:?}");
             }
+            Err(error(cx, LayoutError::TooGeneric(ty)))
         }
-        ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
-            bug!("unexpected type: {ty:?}");
+        ty::ConstKind::Infer(_)
+        | ty::ConstKind::Bound(..)
+        | ty::ConstKind::Placeholder(_)
+        | ty::ConstKind::Error(_) => {
+            // `ty::ConstKind::Error` is handled at the top of `layout_of_uncached`
+            // (via `ty.error_reported()`).
+            bug!("layout_of: unexpected const: {ct:?}");
         }
     }
 }
@@ -193,10 +184,9 @@ fn layout_of_uncached<'tcx>(
     };
     let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value)));
 
-    let univariant =
-        |fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, repr: &ReprOptions, kind| {
-            Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?))
-        };
+    let univariant = |fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, kind| {
+        Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, kind)?))
+    };
     debug_assert!(!ty.has_non_region_infer());
 
     Ok(match *ty.kind() {
@@ -209,12 +199,12 @@ fn layout_of_uncached<'tcx>(
                         &mut layout.backend_repr
                     {
                         if let Some(start) = start {
-                            scalar.valid_range_mut().start = extract_const_value(start, ty, cx)?
+                            scalar.valid_range_mut().start = extract_const_value(cx, ty, start)?
                                 .try_to_bits(tcx, cx.typing_env)
                                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
                         }
                         if let Some(end) = end {
-                            let mut end = extract_const_value(end, ty, cx)?
+                            let mut end = extract_const_value(cx, ty, end)?
                                 .try_to_bits(tcx, cx.typing_env)
                                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
                             if !include_end {
@@ -273,16 +263,11 @@ fn layout_of_uncached<'tcx>(
                 data_ptr.valid_range_mut().start = 1;
             }
 
-            let pointee = tcx.normalize_erasing_regions(cx.typing_env, pointee);
             if pointee.is_sized(tcx, cx.typing_env) {
                 return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
             }
 
-            let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type()
-                // Projection eagerly bails out when the pointee references errors,
-                // fall back to structurally deducing metadata.
-                && !pointee.references_error()
-            {
+            let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
                 let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]);
                 let metadata_ty =
                     match tcx.try_normalize_erasing_regions(cx.typing_env, pointee_metadata) {
@@ -353,7 +338,7 @@ fn layout_of_uncached<'tcx>(
 
         // Arrays and slices.
         ty::Array(element, count) => {
-            let count = extract_const_value(count, ty, cx)?
+            let count = extract_const_value(cx, ty, count)?
                 .try_to_target_usize(tcx)
                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
 
@@ -380,7 +365,7 @@ fn layout_of_uncached<'tcx>(
                 size,
                 max_repr_align: None,
                 unadjusted_abi_align: element.align.abi,
-                randomization_seed: element.randomization_seed.wrapping_add(count),
+                randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)),
             })
         }
         ty::Slice(element) => {
@@ -395,7 +380,9 @@ fn layout_of_uncached<'tcx>(
                 max_repr_align: None,
                 unadjusted_abi_align: element.align.abi,
                 // adding a randomly chosen value to distinguish slices
-                randomization_seed: element.randomization_seed.wrapping_add(0x2dcba99c39784102),
+                randomization_seed: element
+                    .randomization_seed
+                    .wrapping_add(Hash64::new(0x2dcba99c39784102)),
             })
         }
         ty::Str => tcx.mk_layout(LayoutData {
@@ -408,21 +395,14 @@ fn layout_of_uncached<'tcx>(
             max_repr_align: None,
             unadjusted_abi_align: dl.i8_align.abi,
             // another random value
-            randomization_seed: 0xc1325f37d127be22,
+            randomization_seed: Hash64::new(0xc1325f37d127be22),
         }),
 
         // Odd unit types.
-        ty::FnDef(..) => {
-            univariant(IndexSlice::empty(), &ReprOptions::default(), StructKind::AlwaysSized)?
-        }
+        ty::FnDef(..) => univariant(IndexSlice::empty(), StructKind::AlwaysSized)?,
         ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
-            let mut unit = univariant_uninterned(
-                cx,
-                ty,
-                IndexSlice::empty(),
-                &ReprOptions::default(),
-                StructKind::AlwaysSized,
-            )?;
+            let mut unit =
+                univariant_uninterned(cx, ty, IndexSlice::empty(), StructKind::AlwaysSized)?;
             match unit.backend_repr {
                 BackendRepr::Memory { ref mut sized } => *sized = false,
                 _ => bug!(),
@@ -436,7 +416,6 @@ fn layout_of_uncached<'tcx>(
             let tys = args.as_closure().upvar_tys();
             univariant(
                 &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
-                &ReprOptions::default(),
                 StructKind::AlwaysSized,
             )?
         }
@@ -445,7 +424,6 @@ fn layout_of_uncached<'tcx>(
             let tys = args.as_coroutine_closure().upvar_tys();
             univariant(
                 &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
-                &ReprOptions::default(),
                 StructKind::AlwaysSized,
             )?
         }
@@ -454,11 +432,7 @@ fn layout_of_uncached<'tcx>(
             let kind =
                 if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
 
-            univariant(
-                &tys.iter().map(|k| cx.layout_of(k)).try_collect::<IndexVec<_, _>>()?,
-                &ReprOptions::default(),
-                kind,
-            )?
+            univariant(&tys.iter().map(|k| cx.layout_of(k)).try_collect::<IndexVec<_, _>>()?, kind)?
         }
 
         // SIMD vector types.
@@ -585,7 +559,7 @@ fn layout_of_uncached<'tcx>(
                 align,
                 max_repr_align: None,
                 unadjusted_abi_align: align.abi,
-                randomization_seed: e_ly.randomization_seed.wrapping_add(e_len),
+                randomization_seed: e_ly.randomization_seed.wrapping_add(Hash64::new(e_len)),
             })
         }
 
@@ -716,25 +690,30 @@ fn layout_of_uncached<'tcx>(
         }
 
         // Types with no meaningful known layout.
+        ty::Param(_) => {
+            return Err(error(cx, LayoutError::TooGeneric(ty)));
+        }
+
         ty::Alias(..) => {
-            if ty.has_param() {
-                return Err(error(cx, LayoutError::TooGeneric(ty)));
-            }
             // NOTE(eddyb) `layout_of` query should've normalized these away,
             // if that was possible, so there's no reason to try again here.
-            return Err(error(cx, LayoutError::Unknown(ty)));
-        }
-
-        ty::Bound(..) | ty::CoroutineWitness(..) | ty::Infer(_) | ty::Error(_) => {
-            bug!("Layout::compute: unexpected type `{}`", ty)
-        }
-
-        ty::Param(_) => {
-            return Err(error(cx, LayoutError::TooGeneric(ty)));
+            let err = if ty.has_param() {
+                LayoutError::TooGeneric(ty)
+            } else {
+                // This is only reachable with unsatisfiable predicates. For example, if we have
+                // `u8: Iterator`, then we can't compute the layout of `<u8 as Iterator>::Item`.
+                LayoutError::Unknown(ty)
+            };
+            return Err(error(cx, err));
         }
 
-        ty::Placeholder(..) => {
-            return Err(error(cx, LayoutError::Unknown(ty)));
+        ty::Placeholder(..)
+        | ty::Bound(..)
+        | ty::CoroutineWitness(..)
+        | ty::Infer(_)
+        | ty::Error(_) => {
+            // `ty::Error` is handled at the top of this function.
+            bug!("layout_of: unexpected type `{ty}`")
         }
     })
 }
@@ -908,13 +887,7 @@ fn coroutine_layout<'tcx>(
         .chain(iter::once(Ok(tag_layout)))
         .chain(promoted_layouts)
         .try_collect::<IndexVec<_, _>>()?;
-    let prefix = univariant_uninterned(
-        cx,
-        ty,
-        &prefix_layouts,
-        &ReprOptions::default(),
-        StructKind::AlwaysSized,
-    )?;
+    let prefix = univariant_uninterned(cx, ty, &prefix_layouts, StructKind::AlwaysSized)?;
 
     let (prefix_size, prefix_align) = (prefix.size, prefix.align);
 
@@ -979,7 +952,6 @@ fn coroutine_layout<'tcx>(
                 cx,
                 ty,
                 &variant_only_tys.map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
-                &ReprOptions::default(),
                 StructKind::Prefixed(prefix_size, prefix_align.abi),
             )?;
             variant.variants = Variants::Single { index };
@@ -1051,7 +1023,7 @@ fn coroutine_layout<'tcx>(
     };
 
     // this is similar to how ReprOptions populates its field_shuffle_seed
-    let def_hash = tcx.def_path_hash(def_id).0.to_smaller_hash().as_u64();
+    let def_hash = tcx.def_path_hash(def_id).0.to_smaller_hash();
 
     let layout = tcx.mk_layout(LayoutData {
         variants: Variants::Multiple {
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 34f461aac58..7ce72c76e5c 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -109,7 +109,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
 
     #[instrument(level = "trace", skip(self))]
     fn collect_taits_declared_in_body(&mut self) {
-        let body = self.tcx.hir().body_owned_by(self.item).value;
+        let body = self.tcx.hir_body_owned_by(self.item).value;
         struct TaitInBodyFinder<'a, 'tcx> {
             collector: &'a mut OpaqueTypeCollector<'tcx>,
         }
@@ -125,7 +125,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
             #[instrument(level = "trace", skip(self))]
             // Recurse into these, as they are type checked with their parent
             fn visit_nested_body(&mut self, id: rustc_hir::BodyId) {
-                let body = self.collector.tcx.hir().body(id);
+                let body = self.collector.tcx.hir_body(id);
                 self.visit_body(body);
             }
         }
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 6924216bd26..9277226b718 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -126,6 +126,10 @@ pub trait Ty<I: Interner<Ty = Self>>:
         matches!(self.kind(), ty::Infer(ty::TyVar(_)))
     }
 
+    fn is_ty_error(self) -> bool {
+        matches!(self.kind(), ty::Error(_))
+    }
+
     fn is_floating_point(self) -> bool {
         matches!(self.kind(), ty::Float(_) | ty::Infer(ty::FloatVar(_)))
     }
@@ -284,6 +288,10 @@ pub trait Const<I: Interner<Const = Self>>:
     fn is_ct_var(self) -> bool {
         matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_)))
     }
+
+    fn is_ct_error(self) -> bool {
+        matches!(self.kind(), ty::ConstKind::Error(_))
+    }
 }
 
 pub trait ValueConst<I: Interner<ValueConst = Self>>: Copy + Debug + Hash + Eq {
@@ -370,6 +378,13 @@ pub trait Term<I: Interner<Term = Self>>:
         }
     }
 
+    fn is_error(self) -> bool {
+        match self.kind() {
+            ty::TermKind::Ty(ty) => ty.is_ty_error(),
+            ty::TermKind::Const(ct) => ct.is_ct_error(),
+        }
+    }
+
     fn to_alias_term(self) -> Option<ty::AliasTerm<I>> {
         match self.kind() {
             ty::TermKind::Ty(ty) => match ty.kind() {
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 52e4fa19cb0..83631f7fe34 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -14,6 +14,7 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
 use self::TyKind::*;
 pub use self::closure::*;
 use crate::inherent::*;
+#[cfg(feature = "nightly")]
 use crate::visit::TypeVisitable;
 use crate::{self as ty, DebruijnIndex, Interner};
 
diff --git a/config.example.toml b/config.example.toml
index f5395375afe..fd27b24e461 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -729,7 +729,8 @@
 #remap-debuginfo = false
 
 # Link the compiler and LLVM against `jemalloc` instead of the default libc allocator.
-# This option is only tested on Linux and OSX.
+# This option is only tested on Linux and OSX. It can also be configured per-target in the
+# [target.<tuple>] section.
 #jemalloc = false
 
 # Run tests in various test suites with the "nll compare mode" in addition to
@@ -927,6 +928,10 @@
 # order to run `x check`.
 #optimized-compiler-builtins = build.optimized-compiler-builtins (bool)
 
+# Link the compiler and LLVM against `jemalloc` instead of the default libc allocator.
+# This overrides the global `rust.jemalloc` option. See that option for more info.
+#jemalloc = rust.jemalloc (bool)
+
 # =============================================================================
 # Distribution options
 #
diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs
index dbfd2e74abe..17dad3277b9 100644
--- a/library/alloc/src/borrow.rs
+++ b/library/alloc/src/borrow.rs
@@ -340,8 +340,18 @@ where
     }
 }
 
+// `Cow<'_, T>` can only implement `DerefPure` if `<T::Owned as Borrow<T>>` (and `BorrowMut<T>`) is trusted.
+// For now, we restrict `DerefPure for Cow<T>` to `T: Sized` (`T as Borrow<T>` is trusted),
+// `str` (`String as Borrow<str>` is trusted) and `[T]` (`Vec<T> as Borrow<[T]>` is trusted).
+// In the future, a `BorrowPure<T>` trait analogous to `DerefPure` might generalize this.
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
-unsafe impl<B: ?Sized + ToOwned> DerefPure for Cow<'_, B> where B::Owned: Borrow<B> {}
+unsafe impl<T: Clone> DerefPure for Cow<'_, T> {}
+#[cfg(not(no_global_oom_handling))]
+#[unstable(feature = "deref_pure_trait", issue = "87121")]
+unsafe impl DerefPure for Cow<'_, str> {}
+#[cfg(not(no_global_oom_handling))]
+#[unstable(feature = "deref_pure_trait", issue = "87121")]
+unsafe impl<T: Clone> DerefPure for Cow<'_, [T]> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<B: ?Sized> Eq for Cow<'_, B> where B: Eq + ToOwned {}
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index ccfdbf0eb70..34f5c3e94bc 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -1168,6 +1168,7 @@ impl char {
     #[must_use]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[rustc_const_stable(feature = "const_char_is_ascii", since = "1.32.0")]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "char_is_ascii")]
     #[inline]
     pub const fn is_ascii(&self) -> bool {
         *self as u32 <= 0x7F
diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs
index 0c388115908..8090c98e7ed 100644
--- a/library/core/src/iter/adapters/zip.rs
+++ b/library/core/src/iter/adapters/zip.rs
@@ -556,13 +556,13 @@ impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoe
 ///     * `std::iter::ExactSizeIterator::len`
 ///     * `std::iter::Iterator::__iterator_get_unchecked`
 ///     * `std::iter::TrustedRandomAccessNoCoerce::size`
-/// 5. If `T` is a subtype of `Self`, then `self` is allowed to be coerced
+/// 5. If `Self` is a subtype of `T`, then `self` is allowed to be coerced
 ///    to `T`. If `self` is coerced to `T` after `self.__iterator_get_unchecked(idx)` has already
 ///    been called, then no methods except for the ones listed under 4. are allowed to be called
 ///    on the resulting value of type `T`, either. Multiple such coercion steps are allowed.
 ///    Regarding 2. and 3., the number of times `__iterator_get_unchecked(idx)` or `next_back()` is
 ///    called on `self` and the resulting value of type `T` (and on further coercion results with
-///    sub-subtypes) are added together and their sums must not exceed the specified bounds.
+///    super-supertypes) are added together and their sums must not exceed the specified bounds.
 ///
 /// Further, given that these conditions are met, it must guarantee that:
 ///
@@ -570,7 +570,7 @@ impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoe
 /// * It must be safe to call the methods listed above on `self` after calling
 ///   `self.__iterator_get_unchecked(idx)`, assuming that the required traits are implemented.
 /// * It must also be safe to drop `self` after calling `self.__iterator_get_unchecked(idx)`.
-/// * If `T` is a subtype of `Self`, then it must be safe to coerce `self` to `T`.
+/// * If `Self` is a subtype of `T`, then it must be safe to coerce `self` to `T`.
 //
 // FIXME: Clarify interaction with SourceIter/InPlaceIterable. Calling `SourceIter::as_inner`
 // after `__iterator_get_unchecked` is supposed to be allowed.
@@ -580,7 +580,7 @@ impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoe
 pub unsafe trait TrustedRandomAccess: TrustedRandomAccessNoCoerce {}
 
 /// Like [`TrustedRandomAccess`] but without any of the requirements / guarantees around
-/// coercions to subtypes after `__iterator_get_unchecked` (they aren’t allowed here!), and
+/// coercions to supertypes after `__iterator_get_unchecked` (they aren’t allowed here!), and
 /// without the requirement that subtypes / supertypes implement `TrustedRandomAccessNoCoerce`.
 ///
 /// This trait was created in PR #85874 to fix soundness issue #85873 without performance regressions.
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 96a290ad5a0..296b5ebdfaf 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -193,13 +193,13 @@ macro_rules! int_impl {
         /// Basic usage:
         ///
         /// ```
-        /// #![feature(integer_sign_cast)]
         ///
         #[doc = concat!("let n = -1", stringify!($SelfT), ";")]
         ///
         #[doc = concat!("assert_eq!(n.cast_unsigned(), ", stringify!($UnsignedT), "::MAX);")]
         /// ```
-        #[unstable(feature = "integer_sign_cast", issue = "125882")]
+        #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 21bad6705ab..b59451d7c75 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -1633,14 +1633,14 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
         /// Basic usage:
         ///
         /// ```
-        /// #![feature(integer_sign_cast)]
         /// # use std::num::NonZero;
         ///
         #[doc = concat!("let n = NonZero::<", stringify!($Int), ">::MAX;")]
         ///
         #[doc = concat!("assert_eq!(n.cast_signed(), NonZero::new(-1", stringify!($Sint), ").unwrap());")]
         /// ```
-        #[unstable(feature = "integer_sign_cast", issue = "125882")]
+        #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
@@ -2072,14 +2072,14 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
         /// Basic usage:
         ///
         /// ```
-        /// #![feature(integer_sign_cast)]
         /// # use std::num::NonZero;
         ///
         #[doc = concat!("let n = NonZero::new(-1", stringify!($Int), ").unwrap();")]
         ///
         #[doc = concat!("assert_eq!(n.cast_unsigned(), NonZero::<", stringify!($Uint), ">::MAX);")]
         /// ```
-        #[unstable(feature = "integer_sign_cast", issue = "125882")]
+        #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 29f6791ee6a..74d3ae699f6 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -223,13 +223,12 @@ macro_rules! uint_impl {
         /// Basic usage:
         ///
         /// ```
-        /// #![feature(integer_sign_cast)]
-        ///
         #[doc = concat!("let n = ", stringify!($SelfT), "::MAX;")]
         ///
         #[doc = concat!("assert_eq!(n.cast_signed(), -1", stringify!($SignedT), ");")]
         /// ```
-        #[unstable(feature = "integer_sign_cast", issue = "125882")]
+        #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 05c16791ce7..c0ee49fbb30 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -198,7 +198,7 @@ impl str {
     /// Basic usage:
     ///
     /// ```
-    /// use std::str;
+    /// #![feature(inherent_str_constructors)]
     ///
     /// // some bytes, in a vector
     /// let sparkle_heart = vec![240, 159, 146, 150];
@@ -207,13 +207,13 @@ impl str {
     /// let sparkle_heart = str::from_utf8(&sparkle_heart)?;
     ///
     /// assert_eq!("💖", sparkle_heart);
-    /// # Ok::<_, str::Utf8Error>(())
+    /// # Ok::<_, std::str::Utf8Error>(())
     /// ```
     ///
     /// Incorrect bytes:
     ///
     /// ```
-    /// use std::str;
+    /// #![feature(inherent_str_constructors)]
     ///
     /// // some invalid bytes, in a vector
     /// let sparkle_heart = vec![0, 159, 146, 150];
@@ -227,7 +227,7 @@ impl str {
     /// A "stack allocated string":
     ///
     /// ```
-    /// use std::str;
+    /// #![feature(inherent_str_constructors)]
     ///
     /// // some bytes, in a stack-allocated array
     /// let sparkle_heart = [240, 159, 146, 150];
@@ -238,6 +238,7 @@ impl str {
     /// assert_eq!("💖", sparkle_heart);
     /// ```
     #[unstable(feature = "inherent_str_constructors", issue = "131114")]
+    #[rustc_diagnostic_item = "str_inherent_from_utf8"]
     pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
         converts::from_utf8(v)
     }
@@ -249,7 +250,7 @@ impl str {
     /// Basic usage:
     ///
     /// ```
-    /// use std::str;
+    /// #![feature(inherent_str_constructors)]
     ///
     /// // "Hello, Rust!" as a mutable vector
     /// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33];
@@ -263,7 +264,7 @@ impl str {
     /// Incorrect bytes:
     ///
     /// ```
-    /// use std::str;
+    /// #![feature(inherent_str_constructors)]
     ///
     /// // Some invalid bytes in a mutable vector
     /// let mut invalid = vec![128, 223];
@@ -274,6 +275,7 @@ impl str {
     /// errors that can be returned.
     #[unstable(feature = "inherent_str_constructors", issue = "131114")]
     #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")]
+    #[rustc_diagnostic_item = "str_inherent_from_utf8_mut"]
     pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
         converts::from_utf8_mut(v)
     }
@@ -292,7 +294,7 @@ impl str {
     /// Basic usage:
     ///
     /// ```
-    /// use std::str;
+    /// #![feature(inherent_str_constructors)]
     ///
     /// // some bytes, in a vector
     /// let sparkle_heart = vec![240, 159, 146, 150];
@@ -306,6 +308,7 @@ impl str {
     #[inline]
     #[must_use]
     #[unstable(feature = "inherent_str_constructors", issue = "131114")]
+    #[rustc_diagnostic_item = "str_inherent_from_utf8_unchecked"]
     pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
         // SAFETY: converts::from_utf8_unchecked has the same safety requirements as this function.
         unsafe { converts::from_utf8_unchecked(v) }
@@ -321,7 +324,7 @@ impl str {
     /// Basic usage:
     ///
     /// ```
-    /// use std::str;
+    /// #![feature(inherent_str_constructors)]
     ///
     /// let mut heart = vec![240, 159, 146, 150];
     /// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) };
@@ -331,6 +334,7 @@ impl str {
     #[inline]
     #[must_use]
     #[unstable(feature = "inherent_str_constructors", issue = "131114")]
+    #[rustc_diagnostic_item = "str_inherent_from_utf8_unchecked_mut"]
     pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
         // SAFETY: converts::from_utf8_unchecked_mut has the same safety requirements as this function.
         unsafe { converts::from_utf8_unchecked_mut(v) }
diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs
index b289f6026ff..9eb71922218 100644
--- a/library/core/src/ub_checks.rs
+++ b/library/core/src/ub_checks.rs
@@ -65,9 +65,9 @@ macro_rules! assert_unsafe_precondition {
             #[rustc_nounwind]
             const fn precondition_check($($name:$ty),*) {
                 if !$e {
-                    ::core::panicking::panic_nounwind(
-                        concat!("unsafe precondition(s) violated: ", $message)
-                    );
+                    ::core::panicking::panic_nounwind(concat!("unsafe precondition(s) violated: ", $message,
+                        "\n\nThis indicates a bug in the program. \
+                        This Undefined Behavior check is optional, and cannot be relied on for safety."));
                 }
             }
 
diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs
index bdbe3e21994..0af69dff05a 100644
--- a/library/std/src/f16.rs
+++ b/library/std/src/f16.rs
@@ -1321,12 +1321,14 @@ impl f16 {
     /// ```
     /// #![feature(f16)]
     /// #![feature(float_erf)]
+    /// # #[cfg(reliable_f16_math)] {
     /// let x: f16 = 0.123;
     ///
     /// let one = x.erf() + x.erfc();
     /// let abs_difference = (one - 1.0).abs();
     ///
     /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 83b009c86dc..c340b43352f 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -624,20 +624,20 @@ impl File {
         self.inner.datasync()
     }
 
-    /// Acquire an exclusive advisory lock on the file. Blocks until the lock can be acquired.
+    /// Acquire an exclusive lock on the file. Blocks until the lock can be acquired.
     ///
-    /// This acquires an exclusive advisory lock; no other file handle to this file may acquire
-    /// another lock.
+    /// This acquires an exclusive lock; no other file handle to this file may acquire another lock.
     ///
-    /// If this file handle/descriptor, or a clone of it, already holds an advisory lock the exact
-    /// behavior is unspecified and platform dependent, including the possibility that it will
-    /// deadlock. However, if this method returns, then an exclusive lock is held.
+    /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`],
+    /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with
+    /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not
+    /// cause non-lockholders to block.
     ///
-    /// If the file not open for writing, it is unspecified whether this function returns an error.
+    /// If this file handle/descriptor, or a clone of it, already holds an lock the exact behavior
+    /// is unspecified and platform dependent, including the possibility that it will deadlock.
+    /// However, if this method returns, then an exclusive lock is held.
     ///
-    /// Note, this is an advisory lock meant to interact with [`lock_shared`], [`try_lock`],
-    /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
-    /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
+    /// If the file not open for writing, it is unspecified whether this function returns an error.
     ///
     /// The lock will be released when this file (along with any other file descriptors/handles
     /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called.
@@ -648,8 +648,12 @@ impl File {
     /// and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK` flag. Note that,
     /// this [may change in the future][changes].
     ///
+    /// On Windows, locking a file will fail if the file is opened only for append. To lock a file,
+    /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`.
+    ///
     /// [changes]: io#platform-specific-behavior
     ///
+    /// [`lock`]: File::lock
     /// [`lock_shared`]: File::lock_shared
     /// [`try_lock`]: File::try_lock
     /// [`try_lock_shared`]: File::try_lock_shared
@@ -674,18 +678,19 @@ impl File {
         self.inner.lock()
     }
 
-    /// Acquire a shared (non-exclusive) advisory lock on the file. Blocks until the lock can be acquired.
+    /// Acquire a shared (non-exclusive) lock on the file. Blocks until the lock can be acquired.
     ///
-    /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but
-    /// none may hold an exclusive lock at the same time.
+    /// This acquires a shared lock; more than one file handle may hold a shared lock, but none may
+    /// hold an exclusive lock at the same time.
     ///
-    /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact
-    /// behavior is unspecified and platform dependent, including the possibility that it will
-    /// deadlock. However, if this method returns, then a shared lock is held.
+    /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`],
+    /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with
+    /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not
+    /// cause non-lockholders to block.
     ///
-    /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`],
-    /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
-    /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
+    /// If this file handle/descriptor, or a clone of it, already holds an lock, the exact behavior
+    /// is unspecified and platform dependent, including the possibility that it will deadlock.
+    /// However, if this method returns, then a shared lock is held.
     ///
     /// The lock will be released when this file (along with any other file descriptors/handles
     /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called.
@@ -696,9 +701,13 @@ impl File {
     /// and the `LockFileEx` function on Windows. Note that, this
     /// [may change in the future][changes].
     ///
+    /// On Windows, locking a file will fail if the file is opened only for append. To lock a file,
+    /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`.
+    ///
     /// [changes]: io#platform-specific-behavior
     ///
     /// [`lock`]: File::lock
+    /// [`lock_shared`]: File::lock_shared
     /// [`try_lock`]: File::try_lock
     /// [`try_lock_shared`]: File::try_lock_shared
     /// [`unlock`]: File::unlock
@@ -722,24 +731,23 @@ impl File {
         self.inner.lock_shared()
     }
 
-    /// Try to acquire an exclusive advisory lock on the file.
+    /// Try to acquire an exclusive lock on the file.
     ///
     /// Returns `Ok(false)` if a different lock is already held on this file (via another
     /// handle/descriptor).
     ///
-    /// This acquires an exclusive advisory lock; no other file handle to this file may acquire
-    /// another lock.
+    /// This acquires an exclusive lock; no other file handle to this file may acquire another lock.
     ///
-    /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact
-    /// behavior is unspecified and platform dependent, including the possibility that it will
-    /// deadlock. However, if this method returns `Ok(true)`, then it has acquired an exclusive
-    /// lock.
+    /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`],
+    /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with
+    /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not
+    /// cause non-lockholders to block.
     ///
-    /// If the file not open for writing, it is unspecified whether this function returns an error.
+    /// If this file handle/descriptor, or a clone of it, already holds an lock, the exact behavior
+    /// is unspecified and platform dependent, including the possibility that it will deadlock.
+    /// However, if this method returns `Ok(true)`, then it has acquired an exclusive lock.
     ///
-    /// Note, this is an advisory lock meant to interact with [`lock`], [`lock_shared`],
-    /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
-    /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
+    /// If the file not open for writing, it is unspecified whether this function returns an error.
     ///
     /// The lock will be released when this file (along with any other file descriptors/handles
     /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called.
@@ -751,10 +759,14 @@ impl File {
     /// and `LOCKFILE_FAIL_IMMEDIATELY` flags. Note that, this
     /// [may change in the future][changes].
     ///
+    /// On Windows, locking a file will fail if the file is opened only for append. To lock a file,
+    /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`.
+    ///
     /// [changes]: io#platform-specific-behavior
     ///
     /// [`lock`]: File::lock
     /// [`lock_shared`]: File::lock_shared
+    /// [`try_lock`]: File::try_lock
     /// [`try_lock_shared`]: File::try_lock_shared
     /// [`unlock`]: File::unlock
     /// [`read`]: Read::read
@@ -777,22 +789,23 @@ impl File {
         self.inner.try_lock()
     }
 
-    /// Try to acquire a shared (non-exclusive) advisory lock on the file.
+    /// Try to acquire a shared (non-exclusive) lock on the file.
     ///
     /// Returns `Ok(false)` if an exclusive lock is already held on this file (via another
     /// handle/descriptor).
     ///
-    /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but
-    /// none may hold an exclusive lock at the same time.
+    /// This acquires a shared lock; more than one file handle may hold a shared lock, but none may
+    /// hold an exclusive lock at the same time.
+    ///
+    /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`],
+    /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with
+    /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not
+    /// cause non-lockholders to block.
     ///
-    /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is
+    /// If this file handle, or a clone of it, already holds an lock, the exact behavior is
     /// unspecified and platform dependent, including the possibility that it will deadlock.
     /// However, if this method returns `Ok(true)`, then it has acquired a shared lock.
     ///
-    /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`],
-    /// [`try_lock`], and [`unlock`]. Its interactions with other methods, such as [`read`]
-    /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
-    ///
     /// The lock will be released when this file (along with any other file descriptors/handles
     /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called.
     ///
@@ -803,11 +816,15 @@ impl File {
     /// `LOCKFILE_FAIL_IMMEDIATELY` flag. Note that, this
     /// [may change in the future][changes].
     ///
+    /// On Windows, locking a file will fail if the file is opened only for append. To lock a file,
+    /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`.
+    ///
     /// [changes]: io#platform-specific-behavior
     ///
     /// [`lock`]: File::lock
     /// [`lock_shared`]: File::lock_shared
     /// [`try_lock`]: File::try_lock
+    /// [`try_lock_shared`]: File::try_lock_shared
     /// [`unlock`]: File::unlock
     /// [`read`]: Read::read
     /// [`write`]: Write::write
@@ -844,6 +861,9 @@ impl File {
     /// and the `UnlockFile` function on Windows. Note that, this
     /// [may change in the future][changes].
     ///
+    /// On Windows, locking a file will fail if the file is opened only for append. To lock a file,
+    /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`.
+    ///
     /// [changes]: io#platform-specific-behavior
     ///
     /// # Examples
@@ -1229,6 +1249,9 @@ impl Seek for &File {
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
         self.inner.seek(pos)
     }
+    fn stream_position(&mut self) -> io::Result<u64> {
+        self.inner.tell()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1275,6 +1298,9 @@ impl Seek for File {
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
         (&*self).seek(pos)
     }
+    fn stream_position(&mut self) -> io::Result<u64> {
+        (&*self).stream_position()
+    }
 }
 
 #[stable(feature = "io_traits_arc", since = "1.73.0")]
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 318c3508221..661c422811a 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -239,6 +239,7 @@ fn handle_ebadf_lazy<T>(r: io::Result<T>, default: impl FnOnce() -> T) -> io::Re
 /// }
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Stdin")]
 pub struct Stdin {
     inner: &'static Mutex<BufReader<StdinRaw>>,
 }
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index 42aada131da..34f0e89f2f1 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -162,13 +162,6 @@ pub trait FileExt {
         Ok(())
     }
 
-    /// Returns the current position within the file.
-    ///
-    /// This corresponds to the `fd_tell` syscall and is similar to
-    /// `seek` where you offset 0 bytes from the current position.
-    #[doc(alias = "fd_tell")]
-    fn tell(&self) -> io::Result<u64>;
-
     /// Adjusts the flags associated with this file.
     ///
     /// This corresponds to the `fd_fdstat_set_flags` syscall.
@@ -240,10 +233,6 @@ impl FileExt for fs::File {
         self.as_inner().as_inner().pwrite(bufs, offset)
     }
 
-    fn tell(&self) -> io::Result<u64> {
-        self.as_inner().as_inner().tell()
-    }
-
     fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> {
         self.as_inner().as_inner().set_flags(flags)
     }
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 61801db072a..22776ae2bc4 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -255,6 +255,7 @@ pub use crate::panicking::{set_hook, take_hook};
 #[stable(feature = "panic_any", since = "1.51.0")]
 #[inline]
 #[track_caller]
+#[cfg_attr(not(test), rustc_diagnostic_item = "panic_any")]
 pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
     crate::panicking::begin_panic(msg);
 }
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index fd0fd1cb755..bdd4844b651 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -217,6 +217,7 @@ use crate::{fmt, fs, str};
 ///
 /// [`wait`]: Child::wait
 #[stable(feature = "process", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Child")]
 pub struct Child {
     pub(crate) handle: imp::Process,
 
@@ -2115,6 +2116,7 @@ impl Child {
     /// [`ErrorKind`]: io::ErrorKind
     /// [`InvalidInput`]: io::ErrorKind::InvalidInput
     #[stable(feature = "process", since = "1.0.0")]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "child_kill")]
     pub fn kill(&mut self) -> io::Result<()> {
         self.handle.kill()
     }
@@ -2135,6 +2137,7 @@ impl Child {
     /// ```
     #[must_use]
     #[stable(feature = "process_id", since = "1.3.0")]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "child_id")]
     pub fn id(&self) -> u32 {
         self.handle.id()
     }
@@ -2375,6 +2378,7 @@ pub fn exit(code: i32) -> ! {
 /// [panic hook]: crate::panic::set_hook
 #[stable(feature = "process_abort", since = "1.17.0")]
 #[cold]
+#[cfg_attr(not(test), rustc_diagnostic_item = "process_abort")]
 pub fn abort() -> ! {
     crate::sys::abort_internal();
 }
diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs
index 7bc36717f34..d4bf84dc185 100644
--- a/library/std/src/sys/pal/hermit/fs.rs
+++ b/library/std/src/sys/pal/hermit/fs.rs
@@ -421,6 +421,10 @@ impl File {
         Err(Error::from_raw_os_error(22))
     }
 
+    pub fn tell(&self) -> io::Result<u64> {
+        self.seek(SeekFrom::Current(0))
+    }
+
     pub fn duplicate(&self) -> io::Result<File> {
         Err(Error::from_raw_os_error(22))
     }
diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs
index c87a63fde89..4e741943283 100644
--- a/library/std/src/sys/pal/solid/fs.rs
+++ b/library/std/src/sys/pal/solid/fs.rs
@@ -452,8 +452,11 @@ impl File {
             abi::SOLID_FS_Lseek(self.fd.raw(), pos, whence)
         })
         .map_err(|e| e.as_io_error())?;
-
         // Get the new offset
+        self.tell()
+    }
+
+    pub fn tell(&self) -> io::Result<u64> {
         unsafe {
             let mut out_offset = MaybeUninit::uninit();
             error::SolidError::err_if_negative(abi::SOLID_FS_Ftell(
diff --git a/library/std/src/sys/pal/uefi/fs.rs b/library/std/src/sys/pal/uefi/fs.rs
index 9585ec24f68..45e93deffa3 100644
--- a/library/std/src/sys/pal/uefi/fs.rs
+++ b/library/std/src/sys/pal/uefi/fs.rs
@@ -258,6 +258,10 @@ impl File {
         self.0
     }
 
+    pub fn tell(&self) -> io::Result<u64> {
+        self.0
+    }
+
     pub fn duplicate(&self) -> io::Result<File> {
         self.0
     }
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index 16fb207298d..3df460e38b7 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -1437,6 +1437,10 @@ impl File {
         Ok(n as u64)
     }
 
+    pub fn tell(&self) -> io::Result<u64> {
+        self.seek(SeekFrom::Current(0))
+    }
+
     pub fn duplicate(&self) -> io::Result<File> {
         self.0.duplicate().map(File)
     }
diff --git a/library/std/src/sys/pal/unsupported/fs.rs b/library/std/src/sys/pal/unsupported/fs.rs
index 9585ec24f68..45e93deffa3 100644
--- a/library/std/src/sys/pal/unsupported/fs.rs
+++ b/library/std/src/sys/pal/unsupported/fs.rs
@@ -258,6 +258,10 @@ impl File {
         self.0
     }
 
+    pub fn tell(&self) -> io::Result<u64> {
+        self.0
+    }
+
     pub fn duplicate(&self) -> io::Result<File> {
         self.0
     }
diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs
index 11002406d2b..39978346d73 100644
--- a/library/std/src/sys/pal/wasi/fs.rs
+++ b/library/std/src/sys/pal/wasi/fs.rs
@@ -517,6 +517,10 @@ impl File {
         self.fd.seek(pos)
     }
 
+    pub fn tell(&self) -> io::Result<u64> {
+        self.fd.tell()
+    }
+
     pub fn duplicate(&self) -> io::Result<File> {
         // https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-rationale.md#why-no-dup
         unsupported()
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index ff02737dcf8..0ddce30cf8e 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -631,6 +631,10 @@ impl File {
         Ok(newpos as u64)
     }
 
+    pub fn tell(&self) -> io::Result<u64> {
+        self.seek(SeekFrom::Current(0))
+    }
+
     pub fn duplicate(&self) -> io::Result<File> {
         Ok(Self { handle: self.handle.try_clone()? })
     }
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 84cf99b5540..aa08dd7e424 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -16,6 +16,8 @@ use std::process::Stdio;
 use std::{env, fs, str};
 
 use serde_derive::Deserialize;
+#[cfg(feature = "tracing")]
+use tracing::{instrument, span};
 
 use crate::core::build_steps::tool::SourceType;
 use crate::core::build_steps::{dist, llvm};
@@ -30,7 +32,7 @@ use crate::utils::exec::command;
 use crate::utils::helpers::{
     exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
 };
-use crate::{CLang, Compiler, DependencyType, GitRepo, LLVM_TOOLS, Mode};
+use crate::{CLang, Compiler, DependencyType, GitRepo, LLVM_TOOLS, Mode, debug, trace};
 
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Std {
@@ -98,6 +100,7 @@ impl Step for Std {
         run.crate_or_deps("sysroot").path("library")
     }
 
+    #[cfg_attr(feature = "tracing", instrument(level = "trace", name = "Std::make_run", skip_all))]
     fn make_run(run: RunConfig<'_>) {
         let crates = std_crates_for_run_make(&run);
         let builder = run.builder;
@@ -109,6 +112,14 @@ impl Step for Std {
             && builder.download_rustc()
             && builder.config.last_modified_commit(&["library"], "download-rustc", true).is_none();
 
+        trace!("is managed git repo: {}", builder.rust_info().is_managed_git_subrepository());
+        trace!("download_rustc: {}", builder.download_rustc());
+        trace!(
+            "last modified commit: {:?}",
+            builder.config.last_modified_commit(&["library"], "download-rustc", true)
+        );
+        trace!(force_recompile);
+
         run.builder.ensure(Std {
             compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
             target: run.target,
@@ -124,13 +135,26 @@ impl Step for Std {
     /// This will build the standard library for a particular stage of the build
     /// using the `compiler` targeting the `target` architecture. The artifacts
     /// created will also be linked into the sysroot directory.
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "debug",
+            name = "Std::run",
+            skip_all,
+            fields(
+                target = ?self.target,
+                compiler = ?self.compiler,
+                force_recompile = self.force_recompile
+            ),
+        ),
+    )]
     fn run(self, builder: &Builder<'_>) {
         let target = self.target;
         let compiler = self.compiler;
 
         // When using `download-rustc`, we already have artifacts for the host available. Don't
         // recompile them.
-        if builder.download_rustc() && target == builder.build.build
+        if builder.download_rustc() && builder.is_builder_target(target)
             // NOTE: the beta compiler may generate different artifacts than the downloaded compiler, so
             // its artifacts can't be reused.
             && compiler.stage != 0
@@ -148,6 +172,9 @@ impl Step for Std {
         if builder.config.keep_stage.contains(&compiler.stage)
             || builder.config.keep_stage_std.contains(&compiler.stage)
         {
+            trace!(keep_stage = ?builder.config.keep_stage);
+            trace!(keep_stage_std = ?builder.config.keep_stage_std);
+
             builder.info("WARNING: Using a potentially old libstd. This may not behave well.");
 
             builder.ensure(StartupObjects { compiler, target });
@@ -163,7 +190,15 @@ impl Step for Std {
         let mut target_deps = builder.ensure(StartupObjects { compiler, target });
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
+        trace!(?compiler_to_use);
+
         if compiler_to_use != compiler {
+            trace!(
+                ?compiler_to_use,
+                ?compiler,
+                "compiler != compiler_to_use, handling cross-compile scenario"
+            );
+
             builder.ensure(Std::new(compiler_to_use, target));
             let msg = if compiler_to_use.host == target {
                 format!(
@@ -186,12 +221,21 @@ impl Step for Std {
             return;
         }
 
+        trace!(
+            ?compiler_to_use,
+            ?compiler,
+            "compiler == compiler_to_use, handling not-cross-compile scenario"
+        );
+
         target_deps.extend(self.copy_extra_objects(builder, &compiler, target));
 
         // The LLD wrappers and `rust-lld` are self-contained linking components that can be
         // necessary to link the stdlib on some targets. We'll also need to copy these binaries to
         // the `stage0-sysroot` to ensure the linker is found when bootstrapping on such a target.
-        if compiler.stage == 0 && builder.is_builder_target(&compiler.host) {
+        if compiler.stage == 0 && builder.is_builder_target(compiler.host) {
+            trace!(
+                "(build == host) copying linking components to `stage0-sysroot` for bootstrapping"
+            );
             // We want to copy the host `bin` folder within the `rustlib` folder in the sysroot.
             let src_sysroot_bin = builder
                 .rustc_snapshot_sysroot()
@@ -210,6 +254,7 @@ impl Step for Std {
         // with -Zalways-encode-mir. This frees us from the need to have a target linker, and the
         // fact that this is a check build integrates nicely with run_cargo.
         let mut cargo = if self.is_for_mir_opt_tests {
+            trace!("building special sysroot for mir-opt tests");
             let mut cargo = builder::Cargo::new_for_mir_opt_tests(
                 builder,
                 compiler,
@@ -222,6 +267,7 @@ impl Step for Std {
             cargo.arg("--manifest-path").arg(builder.src.join("library/sysroot/Cargo.toml"));
             cargo
         } else {
+            trace!("building regular sysroot");
             let mut cargo = builder::Cargo::new(
                 builder,
                 compiler,
@@ -665,6 +711,19 @@ impl Step for StdLink {
     /// Note that this assumes that `compiler` has already generated the libstd
     /// libraries for `target`, and this method will find them in the relevant
     /// output directory.
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "trace",
+            name = "StdLink::run",
+            skip_all,
+            fields(
+                compiler = ?self.compiler,
+                target_compiler = ?self.target_compiler,
+                target = ?self.target
+            ),
+        ),
+    )]
     fn run(self, builder: &Builder<'_>) {
         let compiler = self.compiler;
         let target_compiler = self.target_compiler;
@@ -822,6 +881,15 @@ impl Step for StartupObjects {
     /// They don't require any library support as they're just plain old object
     /// files, so we just use the nightly snapshot compiler to always build them (as
     /// no other compilers are guaranteed to be available).
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "trace",
+            name = "StartupObjects::run",
+            skip_all,
+            fields(compiler = ?self.compiler, target = ?self.target),
+        ),
+    )]
     fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
         let for_compiler = self.compiler;
         let target = self.target;
@@ -936,6 +1004,15 @@ impl Step for Rustc {
     /// This will build the compiler for a particular stage of the build using
     /// the `compiler` targeting the `target` architecture. The artifacts
     /// created will also be linked into the sysroot directory.
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "debug",
+            name = "Rustc::run",
+            skip_all,
+            fields(previous_compiler = ?self.compiler, target = ?self.target),
+        ),
+    )]
     fn run(self, builder: &Builder<'_>) -> u32 {
         let compiler = self.compiler;
         let target = self.target;
@@ -943,6 +1020,8 @@ impl Step for Rustc {
         // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler,
         // so its artifacts can't be reused.
         if builder.download_rustc() && compiler.stage != 0 {
+            trace!(stage = compiler.stage, "`download_rustc` requested");
+
             let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
             cp_rustc_component_to_ci_sysroot(
                 builder,
@@ -955,6 +1034,8 @@ impl Step for Rustc {
         builder.ensure(Std::new(compiler, target));
 
         if builder.config.keep_stage.contains(&compiler.stage) {
+            trace!(stage = compiler.stage, "`keep-stage` requested");
+
             builder.info("WARNING: Using a potentially old librustc. This may not behave well.");
             builder.info("WARNING: Use `--keep-stage-std` if you want to rebuild the compiler when it changes");
             builder.ensure(RustcLink::from_rustc(self, compiler));
@@ -1260,7 +1341,7 @@ pub fn rustc_cargo_env(
 
     // Build jemalloc on AArch64 with support for page sizes up to 64K
     // See: https://github.com/rust-lang/rust/pull/135081
-    if builder.config.jemalloc
+    if builder.config.jemalloc(target)
         && target.starts_with("aarch64")
         && env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none()
     {
@@ -1374,6 +1455,19 @@ impl Step for RustcLink {
     }
 
     /// Same as `std_link`, only for librustc
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "trace",
+            name = "RustcLink::run",
+            skip_all,
+            fields(
+                compiler = ?self.compiler,
+                previous_stage_compiler = ?self.previous_stage_compiler,
+                target = ?self.target,
+            ),
+        ),
+    )]
     fn run(self, builder: &Builder<'_>) {
         let compiler = self.compiler;
         let previous_stage_compiler = self.previous_stage_compiler;
@@ -1462,6 +1556,19 @@ impl Step for CodegenBackend {
         }
     }
 
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "debug",
+            name = "CodegenBackend::run",
+            skip_all,
+            fields(
+                compiler = ?self.compiler,
+                target = ?self.target,
+                backend = ?self.target,
+            ),
+        ),
+    )]
     fn run(self, builder: &Builder<'_>) {
         let compiler = self.compiler;
         let target = self.target;
@@ -1470,6 +1577,7 @@ impl Step for CodegenBackend {
         builder.ensure(Rustc::new(compiler, target));
 
         if builder.config.keep_stage.contains(&compiler.stage) {
+            trace!("`keep-stage` requested");
             builder.info(
                 "WARNING: Using a potentially old codegen backend. \
                 This may not behave well.",
@@ -1617,6 +1725,15 @@ impl Step for Sysroot {
     /// Returns the sysroot that `compiler` is supposed to use.
     /// For the stage0 compiler, this is stage0-sysroot (because of the initial std build).
     /// For all other stages, it's the same stage directory that the compiler lives in.
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "debug",
+            name = "Sysroot::run",
+            skip_all,
+            fields(compiler = ?self.compiler),
+        ),
+    )]
     fn run(self, builder: &Builder<'_>) -> PathBuf {
         let compiler = self.compiler;
         let host_dir = builder.out.join(compiler.host);
@@ -1633,6 +1750,7 @@ impl Step for Sysroot {
             }
         };
         let sysroot = sysroot_dir(compiler.stage);
+        trace!(stage = ?compiler.stage, ?sysroot);
 
         builder
             .verbose(|| println!("Removing sysroot {} to avoid caching bugs", sysroot.display()));
@@ -1787,10 +1905,20 @@ impl Step for Assemble {
     /// This will assemble a compiler in `build/$host/stage$stage`. The compiler
     /// must have been previously produced by the `stage - 1` builder.build
     /// compiler.
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "debug",
+            name = "Assemble::run",
+            skip_all,
+            fields(target_compiler = ?self.target_compiler),
+        ),
+    )]
     fn run(self, builder: &Builder<'_>) -> Compiler {
         let target_compiler = self.target_compiler;
 
         if target_compiler.stage == 0 {
+            trace!("stage 0 build compiler is always available, simply returning");
             assert_eq!(
                 builder.config.build, target_compiler.host,
                 "Cannot obtain compiler for non-native build triple at stage 0"
@@ -1806,9 +1934,13 @@ impl Step for Assemble {
         t!(fs::create_dir_all(&libdir_bin));
 
         if builder.config.llvm_enabled(target_compiler.host) {
+            trace!("target_compiler.host" = ?target_compiler.host, "LLVM enabled");
+
             let llvm::LlvmResult { llvm_config, .. } =
                 builder.ensure(llvm::Llvm { target: target_compiler.host });
             if !builder.config.dry_run() && builder.config.llvm_tools_enabled {
+                trace!("LLVM tools enabled");
+
                 let llvm_bin_dir =
                     command(llvm_config).arg("--bindir").run_capture_stdout(builder).stdout();
                 let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
@@ -1818,7 +1950,13 @@ impl Step for Assemble {
                 // rustup, and lets developers use a locally built toolchain to
                 // build projects that expect llvm tools to be present in the sysroot
                 // (e.g. the `bootimage` crate).
+
+                #[cfg(feature = "tracing")]
+                let _llvm_tools_span =
+                    span!(tracing::Level::TRACE, "installing llvm tools to sysroot", ?libdir_bin)
+                        .entered();
                 for tool in LLVM_TOOLS {
+                    trace!("installing `{tool}`");
                     let tool_exe = exe(tool, target_compiler.host);
                     let src_path = llvm_bin_dir.join(&tool_exe);
                     // When using `download-ci-llvm`, some of the tools
@@ -1838,6 +1976,7 @@ impl Step for Assemble {
 
         let maybe_install_llvm_bitcode_linker = |compiler| {
             if builder.config.llvm_bitcode_linker_enabled {
+                trace!("llvm-bitcode-linker enabled, installing");
                 let src_path = builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker {
                     compiler,
                     target: target_compiler.host,
@@ -1850,6 +1989,8 @@ impl Step for Assemble {
 
         // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0.
         if builder.download_rustc() {
+            trace!("`download-rustc` requested, reusing CI compiler for stage > 0");
+
             builder.ensure(Std::new(target_compiler, target_compiler.host));
             let sysroot =
                 builder.ensure(Sysroot { compiler: target_compiler, force_recompile: false });
@@ -1879,16 +2020,17 @@ impl Step for Assemble {
         //
         // FIXME: It may be faster if we build just a stage 1 compiler and then
         //        use that to bootstrap this compiler forward.
+        debug!(
+            "ensuring build compiler is available: compiler(stage = {}, host = {:?})",
+            target_compiler.stage - 1,
+            builder.config.build,
+        );
         let mut build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build);
 
         // Build enzyme
-        let enzyme_install = if builder.config.llvm_enzyme {
-            Some(builder.ensure(llvm::Enzyme { target: build_compiler.host }))
-        } else {
-            None
-        };
-
-        if let Some(enzyme_install) = enzyme_install {
+        if builder.config.llvm_enzyme {
+            debug!("`llvm_enzyme` requested");
+            let enzyme_install = builder.ensure(llvm::Enzyme { target: build_compiler.host });
             let lib_ext = std::env::consts::DLL_EXTENSION;
             let src_lib = enzyme_install.join("build/Enzyme/libEnzyme-19").with_extension(lib_ext);
             let libdir = builder.sysroot_target_libdir(build_compiler, build_compiler.host);
@@ -1905,13 +2047,27 @@ impl Step for Assemble {
         // link to these. (FIXME: Is that correct? It seems to be correct most
         // of the time but I think we do link to these for stage2/bin compilers
         // when not performing a full bootstrap).
+        debug!(
+            ?build_compiler,
+            "target_compiler.host" = ?target_compiler.host,
+            "building compiler libraries to link to"
+        );
         let actual_stage = builder.ensure(Rustc::new(build_compiler, target_compiler.host));
         // Current build_compiler.stage might be uplifted instead of being built; so update it
         // to not fail while linking the artifacts.
+        debug!(
+            "(old) build_compiler.stage" = build_compiler.stage,
+            "(adjusted) build_compiler.stage" = actual_stage,
+            "temporarily adjusting `build_compiler.stage` to account for uplifted libraries"
+        );
         build_compiler.stage = actual_stage;
 
+        #[cfg(feature = "tracing")]
+        let _codegen_backend_span =
+            span!(tracing::Level::DEBUG, "building requested codegen backends").entered();
         for backend in builder.config.codegen_backends(target_compiler.host) {
             if backend == "llvm" {
+                debug!("llvm codegen backend is already built as part of rustc");
                 continue; // Already built as part of rustc
             }
 
@@ -1921,6 +2077,8 @@ impl Step for Assemble {
                 backend: backend.clone(),
             });
         }
+        #[cfg(feature = "tracing")]
+        drop(_codegen_backend_span);
 
         let stage = target_compiler.stage;
         let host = target_compiler.host;
@@ -1980,6 +2138,7 @@ impl Step for Assemble {
             }
         }
 
+        debug!("copying codegen backends to sysroot");
         copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler);
 
         if builder.config.lld_enabled {
@@ -1990,6 +2149,11 @@ impl Step for Assemble {
         }
 
         if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled {
+            debug!(
+                "llvm and llvm tools enabled; copying `llvm-objcopy` as `rust-objcopy` to \
+                workaround faulty homebrew `strip`s"
+            );
+
             // `llvm-strip` is used by rustc, which is actually just a symlink to `llvm-objcopy`, so
             // copy and rename `llvm-objcopy`.
             //
@@ -2022,6 +2186,11 @@ impl Step for Assemble {
 
         // Ensure that `libLLVM.so` ends up in the newly build compiler directory,
         // so that it can be found when the newly built `rustc` is run.
+        debug!(
+            "target_compiler.host" = ?target_compiler.host,
+            ?sysroot,
+            "ensuring availability of `libLLVM.so` in compiler directory"
+        );
         dist::maybe_install_llvm_runtime(builder, target_compiler.host, &sysroot);
         dist::maybe_install_llvm_target(builder, target_compiler.host, &sysroot);
 
@@ -2031,6 +2200,7 @@ impl Step for Assemble {
         let bindir = sysroot.join("bin");
         t!(fs::create_dir_all(bindir));
         let compiler = builder.rustc(target_compiler);
+        debug!(src = ?rustc, dst = ?compiler, "linking compiler binary itself");
         builder.copy_link(&rustc, &compiler);
 
         target_compiler
@@ -2315,7 +2485,7 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path)
     // FIXME: to make things simpler for now, limit this to the host and target where we know
     // `strip -g` is both available and will fix the issue, i.e. on a x64 linux host that is not
     // cross-compiling. Expand this to other appropriate targets in the future.
-    if target != "x86_64-unknown-linux-gnu" || !builder.is_builder_target(&target) || !path.exists()
+    if target != "x86_64-unknown-linux-gnu" || !builder.is_builder_target(target) || !path.exists()
     {
         return;
     }
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index ae3761a97e5..85b224771bb 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -16,10 +16,12 @@ use std::{env, fs};
 
 use object::BinaryFormat;
 use object::read::archive::ArchiveFile;
+#[cfg(feature = "tracing")]
+use tracing::instrument;
 
 use crate::core::build_steps::doc::DocumentationFormat;
 use crate::core::build_steps::tool::{self, Tool};
-use crate::core::build_steps::vendor::default_paths_to_vendor;
+use crate::core::build_steps::vendor::{VENDOR_DIR, Vendor};
 use crate::core::build_steps::{compile, llvm};
 use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
@@ -30,7 +32,7 @@ use crate::utils::helpers::{
     exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit,
 };
 use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
-use crate::{Compiler, DependencyType, LLVM_TOOLS, Mode};
+use crate::{Compiler, DependencyType, LLVM_TOOLS, Mode, trace};
 
 pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
     format!("{}-{}", component, builder.rust_package_vers())
@@ -582,7 +584,7 @@ impl Step for DebuggerScripts {
 fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
     // The only true set of target libraries came from the build triple, so
     // let's reduce redundant work by only producing archives from that host.
-    if !builder.is_builder_target(&compiler.host) {
+    if !builder.is_builder_target(compiler.host) {
         builder.info("\tskipping, not a build host");
         true
     } else {
@@ -637,7 +639,7 @@ fn copy_target_libs(
     for (path, dependency_type) in builder.read_stamp_file(stamp) {
         if dependency_type == DependencyType::TargetSelfContained {
             builder.copy_link(&path, &self_contained_dst.join(path.file_name().unwrap()));
-        } else if dependency_type == DependencyType::Target || builder.is_builder_target(&target) {
+        } else if dependency_type == DependencyType::Target || builder.is_builder_target(target) {
             builder.copy_link(&path, &dst.join(path.file_name().unwrap()));
         }
     }
@@ -786,7 +788,7 @@ impl Step for Analysis {
     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
         let compiler = self.compiler;
         let target = self.target;
-        if !builder.is_builder_target(&compiler.host) {
+        if !builder.is_builder_target(compiler.host) {
             return None;
         }
 
@@ -1050,19 +1052,6 @@ impl Step for PlainSourceTarball {
         if builder.config.dist_vendor {
             builder.require_and_update_all_submodules();
 
-            // Vendor all Cargo dependencies
-            let mut cmd = command(&builder.initial_cargo);
-            cmd.arg("vendor").arg("--versioned-dirs");
-
-            for (p, _) in default_paths_to_vendor(builder) {
-                cmd.arg("--sync").arg(p);
-            }
-
-            cmd
-                // Will read the libstd Cargo.toml which uses the unstable `public-dependency` feature.
-                .env("RUSTC_BOOTSTRAP", "1")
-                .current_dir(plain_dst_src);
-
             // Vendor packages that are required by opt-dist to collect PGO profiles.
             let pkgs_for_pgo_training = build_helper::LLVM_PGO_CRATES
                 .iter()
@@ -1074,15 +1063,18 @@ impl Step for PlainSourceTarball {
                     manifest_path.push("Cargo.toml");
                     manifest_path
                 });
-            for manifest_path in pkgs_for_pgo_training {
-                cmd.arg("--sync").arg(manifest_path);
-            }
 
-            let config = cmd.run_capture(builder).stdout();
+            // Vendor all Cargo dependencies
+            let vendor = builder.ensure(Vendor {
+                sync_args: pkgs_for_pgo_training.collect(),
+                versioned_dirs: true,
+                root_dir: plain_dst_src.into(),
+                output_dir: VENDOR_DIR.into(),
+            });
 
             let cargo_config_dir = plain_dst_src.join(".cargo");
             builder.create_dir(&cargo_config_dir);
-            builder.create(&cargo_config_dir.join("config.toml"), &config);
+            builder.create(&cargo_config_dir.join("config.toml"), &vendor.config);
         }
 
         // Delete extraneous directories
@@ -2029,6 +2021,15 @@ fn install_llvm_file(
 /// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
 ///
 /// Returns whether the files were actually copied.
+#[cfg_attr(
+    feature = "tracing",
+    instrument(
+        level = "trace",
+        name = "maybe_install_llvm",
+        skip_all,
+        fields(target = ?target, dst_libdir = ?dst_libdir, install_symlink = install_symlink),
+    ),
+)]
 fn maybe_install_llvm(
     builder: &Builder<'_>,
     target: TargetSelection,
@@ -2052,6 +2053,7 @@ fn maybe_install_llvm(
     // If the LLVM is coming from ourselves (just from CI) though, we
     // still want to install it, as it otherwise won't be available.
     if builder.is_system_llvm(target) {
+        trace!("system LLVM requested, no install");
         return false;
     }
 
@@ -2070,6 +2072,7 @@ fn maybe_install_llvm(
     } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) =
         llvm::prebuilt_llvm_config(builder, target, true)
     {
+        trace!("LLVM already built, installing LLVM files");
         let mut cmd = command(llvm_config);
         cmd.arg("--libfiles");
         builder.verbose(|| println!("running {cmd:?}"));
@@ -2092,6 +2095,19 @@ fn maybe_install_llvm(
 }
 
 /// Maybe add libLLVM.so to the target lib-dir for linking.
+#[cfg_attr(
+    feature = "tracing",
+    instrument(
+        level = "trace",
+        name = "maybe_install_llvm_target",
+        skip_all,
+        fields(
+            llvm_link_shared = ?builder.llvm_link_shared(),
+            target = ?target,
+            sysroot = ?sysroot,
+        ),
+    ),
+)]
 pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
     let dst_libdir = sysroot.join("lib/rustlib").join(target).join("lib");
     // We do not need to copy LLVM files into the sysroot if it is not
@@ -2103,6 +2119,19 @@ pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection,
 }
 
 /// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
+#[cfg_attr(
+    feature = "tracing",
+    instrument(
+        level = "trace",
+        name = "maybe_install_llvm_runtime",
+        skip_all,
+        fields(
+            llvm_link_shared = ?builder.llvm_link_shared(),
+            target = ?target,
+            sysroot = ?sysroot,
+        ),
+    ),
+)]
 pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
     let dst_libdir =
         sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 23bb47dcc58..aee56fe78e2 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -577,6 +577,10 @@ impl Step for Std {
 
     fn make_run(run: RunConfig<'_>) {
         let crates = compile::std_crates_for_run_make(&run);
+        let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false);
+        if crates.is_empty() && target_is_no_std {
+            return;
+        }
         run.builder.ensure(Std {
             stage: run.builder.top_stage,
             target: run.target,
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 18da0e8252b..3025f955660 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -16,6 +16,8 @@ use std::{env, fs};
 
 use build_helper::ci::CiEnv;
 use build_helper::git::get_closest_merge_commit;
+#[cfg(feature = "tracing")]
+use tracing::instrument;
 
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::core::config::{Config, TargetSelection};
@@ -24,7 +26,7 @@ use crate::utils::exec::command;
 use crate::utils::helpers::{
     self, exe, get_clang_cl_resource_dir, t, unhashed_basename, up_to_date,
 };
-use crate::{CLang, GitRepo, Kind};
+use crate::{CLang, GitRepo, Kind, trace};
 
 #[derive(Clone)]
 pub struct LlvmResult {
@@ -516,7 +518,7 @@ impl Step for Llvm {
         }
 
         // https://llvm.org/docs/HowToCrossCompileLLVM.html
-        if !builder.is_builder_target(&target) {
+        if !builder.is_builder_target(target) {
             let LlvmResult { llvm_config, .. } =
                 builder.ensure(Llvm { target: builder.config.build });
             if !builder.config.dry_run() {
@@ -668,7 +670,7 @@ fn configure_cmake(
     }
     cfg.target(&target.triple).host(&builder.config.build.triple);
 
-    if !builder.is_builder_target(&target) {
+    if !builder.is_builder_target(target) {
         cfg.define("CMAKE_CROSSCOMPILING", "True");
 
         if target.contains("netbsd") {
@@ -934,6 +936,15 @@ impl Step for Enzyme {
     }
 
     /// Compile Enzyme for `target`.
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "debug",
+            name = "Enzyme::run",
+            skip_all,
+            fields(target = ?self.target),
+        ),
+    )]
     fn run(self, builder: &Builder<'_>) -> PathBuf {
         builder.require_submodule(
             "src/tools/enzyme",
@@ -959,7 +970,9 @@ impl Step for Enzyme {
         let out_dir = builder.enzyme_out(target);
         let stamp = BuildStamp::new(&out_dir).with_prefix("enzyme").add_stamp(smart_stamp_hash);
 
+        trace!("checking build stamp to see if we need to rebuild enzyme artifacts");
         if stamp.is_up_to_date() {
+            trace!(?out_dir, "enzyme build artifacts are up to date");
             if stamp.stamp().is_empty() {
                 builder.info(
                     "Could not determine the Enzyme submodule commit hash. \
@@ -973,6 +986,7 @@ impl Step for Enzyme {
             return out_dir;
         }
 
+        trace!(?target, "(re)building enzyme artifacts");
         builder.info(&format!("Building Enzyme for {}", target));
         t!(stamp.remove());
         let _time = helpers::timeit(builder);
@@ -994,6 +1008,7 @@ impl Step for Enzyme {
             (true, false) => "Release",
             (true, true) => "RelWithDebInfo",
         };
+        trace!(?profile);
 
         cfg.out_dir(&out_dir)
             .profile(profile)
@@ -1118,7 +1133,7 @@ impl Step for Lld {
             .define("LLVM_CMAKE_DIR", llvm_cmake_dir)
             .define("LLVM_INCLUDE_TESTS", "OFF");
 
-        if !builder.is_builder_target(&target) {
+        if !builder.is_builder_target(target) {
             // Use the host llvm-tblgen binary.
             cfg.define(
                 "LLVM_TABLEGEN_EXE",
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index 167b8a5b168..2b17e02cae5 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -9,6 +9,7 @@ use crate::Mode;
 use crate::core::build_steps::dist::distdir;
 use crate::core::build_steps::test;
 use crate::core::build_steps::tool::{self, SourceType, Tool};
+use crate::core::build_steps::vendor::{Vendor, default_paths_to_vendor};
 use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::core::config::flags::get_completion;
@@ -212,11 +213,39 @@ impl Step for GenerateCopyright {
         let dest = builder.out.join("COPYRIGHT.html");
         let dest_libstd = builder.out.join("COPYRIGHT-library.html");
 
+        let paths_to_vendor = default_paths_to_vendor(builder);
+        for (_, submodules) in &paths_to_vendor {
+            for submodule in submodules {
+                builder.build.require_submodule(submodule, None);
+            }
+        }
+        let cargo_manifests = paths_to_vendor
+            .into_iter()
+            .map(|(path, _submodules)| path.to_str().unwrap().to_string())
+            .inspect(|path| assert!(!path.contains(','), "{path} contains a comma in its name"))
+            .collect::<Vec<_>>()
+            .join(",");
+
+        let vendored_sources = if let Some(path) = builder.vendored_crates_path() {
+            path
+        } else {
+            let cache_dir = builder.out.join("tmp").join("generate-copyright-vendor");
+            builder.ensure(Vendor {
+                sync_args: Vec::new(),
+                versioned_dirs: true,
+                root_dir: builder.src.clone(),
+                output_dir: cache_dir.clone(),
+            });
+            cache_dir
+        };
+
         let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
+        cmd.env("CARGO_MANIFESTS", &cargo_manifests);
         cmd.env("LICENSE_METADATA", &license_metadata);
         cmd.env("DEST", &dest);
         cmd.env("DEST_LIBSTD", &dest_libstd);
-        cmd.env("OUT_DIR", &builder.out);
+        cmd.env("SRC_DIR", &builder.src);
+        cmd.env("VENDOR_DIR", &vendored_sources);
         cmd.env("CARGO", &builder.initial_cargo);
         // it is important that generate-copyright runs from the root of the
         // source tree, because it uses relative paths
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 26ed0e5deaa..b3f4a7bad99 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2743,7 +2743,7 @@ impl Step for Crate {
             cargo
         } else {
             // Also prepare a sysroot for the target.
-            if !builder.is_builder_target(&target) {
+            if !builder.is_builder_target(target) {
                 builder.ensure(compile::Std::new(compiler, target).force_recompile(true));
                 builder.ensure(RemoteCopyLibs { compiler, target });
             }
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 1291a634a6f..75bfff34086 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1,6 +1,9 @@
 use std::path::PathBuf;
 use std::{env, fs};
 
+#[cfg(feature = "tracing")]
+use tracing::instrument;
+
 use crate::core::build_steps::compile::is_lto_stage;
 use crate::core::build_steps::toolstate::ToolState;
 use crate::core::build_steps::{compile, llvm};
@@ -304,6 +307,14 @@ macro_rules! bootstrap_tool {
                 });
             }
 
+            #[cfg_attr(
+                feature = "tracing",
+                instrument(
+                    level = "debug",
+                    name = $tool_name,
+                    skip_all,
+                ),
+            )]
             fn run(self, builder: &Builder<'_>) -> PathBuf {
                 $(
                     for submodule in $submodules {
@@ -643,7 +654,7 @@ impl Step for Rustdoc {
         // to build rustdoc.
         //
         let mut features = Vec::new();
-        if builder.config.jemalloc {
+        if builder.config.jemalloc(target) {
             features.push("jemalloc".to_string());
         }
 
@@ -758,6 +769,15 @@ impl Step for LldWrapper {
         run.never()
     }
 
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "debug",
+            name = "LldWrapper::run",
+            skip_all,
+            fields(build_compiler = ?self.build_compiler, target_compiler = ?self.target_compiler),
+        ),
+    )]
     fn run(self, builder: &Builder<'_>) {
         if builder.config.dry_run() {
             return;
@@ -914,6 +934,10 @@ impl Step for LlvmBitcodeLinker {
         });
     }
 
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(level = "debug", name = "LlvmBitcodeLinker::run", skip_all)
+    )]
     fn run(self, builder: &Builder<'_>) -> PathBuf {
         let bin_name = "llvm-bitcode-linker";
 
diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs
index 26d0f100ffd..410dbc04f03 100644
--- a/src/bootstrap/src/core/build_steps/vendor.rs
+++ b/src/bootstrap/src/core/build_steps/vendor.rs
@@ -4,6 +4,8 @@ use crate::core::build_steps::tool::SUBMODULES_FOR_RUSTBOOK;
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::utils::exec::command;
 
+pub const VENDOR_DIR: &str = "vendor";
+
 /// Returns the cargo workspaces to vendor for `x vendor` and dist tarballs.
 ///
 /// Returns a `Vec` of `(path_to_manifest, submodules_required)` where
@@ -29,13 +31,14 @@ pub fn default_paths_to_vendor(builder: &Builder<'_>) -> Vec<(PathBuf, Vec<&'sta
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub(crate) struct Vendor {
-    sync_args: Vec<PathBuf>,
-    versioned_dirs: bool,
-    root_dir: PathBuf,
+    pub(crate) sync_args: Vec<PathBuf>,
+    pub(crate) versioned_dirs: bool,
+    pub(crate) root_dir: PathBuf,
+    pub(crate) output_dir: PathBuf,
 }
 
 impl Step for Vendor {
-    type Output = ();
+    type Output = VendorOutput;
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
@@ -48,10 +51,13 @@ impl Step for Vendor {
             sync_args: run.builder.config.cmd.vendor_sync_args(),
             versioned_dirs: run.builder.config.cmd.vendor_versioned_dirs(),
             root_dir: run.builder.src.clone(),
+            output_dir: run.builder.src.join(VENDOR_DIR),
         });
     }
 
     fn run(self, builder: &Builder<'_>) -> Self::Output {
+        builder.info(&format!("Vendoring sources to {:?}", self.root_dir));
+
         let mut cmd = command(&builder.initial_cargo);
         cmd.arg("vendor");
 
@@ -81,8 +87,14 @@ impl Step for Vendor {
         // which uses the unstable `public-dependency` feature.
         cmd.env("RUSTC_BOOTSTRAP", "1");
 
-        cmd.current_dir(self.root_dir);
+        cmd.current_dir(self.root_dir).arg(&self.output_dir);
 
-        cmd.run(builder);
+        let config = cmd.run_capture_stdout(builder);
+        VendorOutput { config: config.stdout() }
     }
 }
+
+#[derive(Debug, Clone)]
+pub(crate) struct VendorOutput {
+    pub(crate) config: String,
+}
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index 59680af0062..1ec3e601cad 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -924,8 +924,7 @@ impl Builder<'_> {
 
         if self.config.rust_remap_debuginfo {
             let mut env_var = OsString::new();
-            if self.config.vendor {
-                let vendor = self.build.src.join("vendor");
+            if let Some(vendor) = self.build.vendored_crates_path() {
                 env_var.push(vendor);
                 env_var.push("=/rust/deps");
             } else {
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 52876c3fb3f..daef8fa3c8a 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -10,6 +10,8 @@ use std::time::{Duration, Instant};
 use std::{env, fs};
 
 use clap::ValueEnum;
+#[cfg(feature = "tracing")]
+use tracing::instrument;
 
 pub use self::cargo::{Cargo, cargo_profile_var};
 pub use crate::Compiler;
@@ -21,7 +23,7 @@ use crate::core::config::{DryRun, TargetSelection};
 use crate::utils::cache::Cache;
 use crate::utils::exec::{BootstrapCommand, command};
 use crate::utils::helpers::{self, LldThreads, add_dylib_path, exe, libdir, linker_args, t};
-use crate::{Build, Crate};
+use crate::{Build, Crate, trace};
 
 mod cargo;
 
@@ -1218,6 +1220,19 @@ impl<'a> Builder<'a> {
     /// compiler will run on, *not* the target it will build code for). Explicitly does not take
     /// `Compiler` since all `Compiler` instances are meant to be obtained through this function,
     /// since it ensures that they are valid (i.e., built and assembled).
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "trace",
+            name = "Builder::compiler",
+            target = "COMPILER",
+            skip_all,
+            fields(
+                stage = stage,
+                host = ?host,
+            ),
+        ),
+    )]
     pub fn compiler(&self, stage: u32, host: TargetSelection) -> Compiler {
         self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } })
     }
@@ -1233,19 +1248,39 @@ impl<'a> Builder<'a> {
     /// sysroot.
     ///
     /// See `force_use_stage1` and `force_use_stage2` for documentation on what each argument is.
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "trace",
+            name = "Builder::compiler_for",
+            target = "COMPILER_FOR",
+            skip_all,
+            fields(
+                stage = stage,
+                host = ?host,
+                target = ?target,
+            ),
+        ),
+    )]
     pub fn compiler_for(
         &self,
         stage: u32,
         host: TargetSelection,
         target: TargetSelection,
     ) -> Compiler {
-        if self.build.force_use_stage2(stage) {
+        #![allow(clippy::let_and_return)]
+        let resolved_compiler = if self.build.force_use_stage2(stage) {
+            trace!(target: "COMPILER_FOR", ?stage, "force_use_stage2");
             self.compiler(2, self.config.build)
         } else if self.build.force_use_stage1(stage, target) {
+            trace!(target: "COMPILER_FOR", ?stage, "force_use_stage1");
             self.compiler(1, self.config.build)
         } else {
+            trace!(target: "COMPILER_FOR", ?stage, ?host, "no force, fallback to `compiler()`");
             self.compiler(stage, host)
-        }
+        };
+        trace!(target: "COMPILER_FOR", ?resolved_compiler);
+        resolved_compiler
     }
 
     pub fn sysroot(&self, compiler: Compiler) -> PathBuf {
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 5e3e0ef654f..445b5dfbeab 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -1080,7 +1080,7 @@ fn test_is_builder_target() {
         let build = Build::new(config);
         let builder = Builder::new(&build);
 
-        assert!(builder.is_builder_target(&target1));
-        assert!(!builder.is_builder_target(&target2));
+        assert!(builder.is_builder_target(target1));
+        assert!(!builder.is_builder_target(target2));
     }
 }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 62625fc3660..64a510240f8 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -325,6 +325,9 @@ pub struct Config {
     pub hosts: Vec<TargetSelection>,
     pub targets: Vec<TargetSelection>,
     pub local_rebuild: bool,
+    #[cfg(not(test))]
+    jemalloc: bool,
+    #[cfg(test)]
     pub jemalloc: bool,
     pub control_flow_guard: bool,
     pub ehcont_guard: bool,
@@ -643,6 +646,7 @@ pub struct Target {
     pub no_std: bool,
     pub codegen_backends: Option<Vec<String>>,
     pub optimized_compiler_builtins: Option<bool>,
+    pub jemalloc: Option<bool>,
 }
 
 impl Target {
@@ -1234,6 +1238,7 @@ define_config! {
         codegen_backends: Option<Vec<String>> = "codegen-backends",
         runner: Option<String> = "runner",
         optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
+        jemalloc: Option<bool> = "jemalloc",
     }
 }
 
@@ -2161,6 +2166,7 @@ impl Config {
                 target.profiler = cfg.profiler;
                 target.rpath = cfg.rpath;
                 target.optimized_compiler_builtins = cfg.optimized_compiler_builtins;
+                target.jemalloc = cfg.jemalloc;
 
                 if let Some(ref backends) = cfg.codegen_backends {
                     let available_backends = ["llvm", "cranelift", "gcc"];
@@ -2726,6 +2732,10 @@ impl Config {
             .unwrap_or(&self.rust_codegen_backends)
     }
 
+    pub fn jemalloc(&self, target: TargetSelection) -> bool {
+        self.target_config.get(&target).and_then(|cfg| cfg.jemalloc).unwrap_or(self.jemalloc)
+    }
+
     pub fn default_codegen_backend(&self, target: TargetSelection) -> Option<String> {
         self.codegen_backends(target).first().cloned()
     }
@@ -2747,6 +2757,15 @@ impl Config {
     /// tarball). Typically [`crate::Build::require_submodule`] should be
     /// used instead to provide a nice error to the user if the submodule is
     /// missing.
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "trace",
+            name = "Config::update_submodule",
+            skip_all,
+            fields(relative_path = ?relative_path),
+        ),
+    )]
     pub(crate) fn update_submodule(&self, relative_path: &str) {
         if !self.submodules() {
             return;
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 9e4a0816e0d..241b7386d18 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -329,7 +329,7 @@ than building it.
         if target.contains("musl") && !target.contains("unikraft") {
             // If this is a native target (host is also musl) and no musl-root is given,
             // fall back to the system toolchain in /usr before giving up
-            if build.musl_root(*target).is_none() && build.is_builder_target(target) {
+            if build.musl_root(*target).is_none() && build.is_builder_target(*target) {
                 let target = build.config.target_config.entry(*target).or_default();
                 target.musl_root = Some("/usr".into());
             }
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 7cd8aacf0d6..dfaf0418d9a 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -50,6 +50,8 @@ pub use utils::change_tracker::{
     CONFIG_CHANGE_HISTORY, find_recent_config_change_ids, human_readable_changes,
 };
 
+use crate::core::build_steps::vendor::VENDOR_DIR;
+
 const LLVM_TOOLS: &[&str] = &[
     "llvm-cov",      // used to generate coverage report
     "llvm-nm",       // used to inspect binaries; it shows symbol names, their sizes and visibility
@@ -469,6 +471,15 @@ impl Build {
     ///
     /// The given `err_hint` will be shown to the user if the submodule is not
     /// checked out and submodule management is disabled.
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "trace",
+            name = "Build::require_submodule",
+            skip_all,
+            fields(submodule = submodule),
+        ),
+    )]
     pub fn require_submodule(&self, submodule: &str, err_hint: Option<&str>) {
         // When testing bootstrap itself, it is much faster to ignore
         // submodules. Almost all Steps work fine without their submodules.
@@ -677,7 +688,7 @@ impl Build {
             crates.is_empty() || possible_features_by_crates.contains(feature)
         };
         let mut features = vec![];
-        if self.config.jemalloc && check("jemalloc") {
+        if self.config.jemalloc(target) && check("jemalloc") {
             features.push("jemalloc");
         }
         if (self.config.llvm_enabled(target) || kind == Kind::Check) && check("llvm") {
@@ -739,7 +750,7 @@ impl Build {
     /// Note that if LLVM is configured externally then the directory returned
     /// will likely be empty.
     fn llvm_out(&self, target: TargetSelection) -> PathBuf {
-        if self.config.llvm_from_ci && self.is_builder_target(&target) {
+        if self.config.llvm_from_ci && self.is_builder_target(target) {
             self.config.ci_llvm_root()
         } else {
             self.out.join(target).join("llvm")
@@ -782,6 +793,11 @@ impl Build {
         self.out.join(target).join("md-doc")
     }
 
+    /// Path to the vendored Rust crates.
+    fn vendored_crates_path(&self) -> Option<PathBuf> {
+        if self.config.vendor { Some(self.src.join(VENDOR_DIR)) } else { None }
+    }
+
     /// Returns `true` if this is an external version of LLVM not managed by bootstrap.
     /// In particular, we expect llvm sources to be available when this is false.
     ///
@@ -789,7 +805,7 @@ impl Build {
     fn is_system_llvm(&self, target: TargetSelection) -> bool {
         match self.config.target_config.get(&target) {
             Some(Target { llvm_config: Some(_), .. }) => {
-                let ci_llvm = self.config.llvm_from_ci && self.is_builder_target(&target);
+                let ci_llvm = self.config.llvm_from_ci && self.is_builder_target(target);
                 !ci_llvm
             }
             // We're building from the in-tree src/llvm-project sources.
@@ -1277,7 +1293,7 @@ Executed at: {executed_at}"#,
             // 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())
-        } else if !self.is_builder_target(&target)
+        } else if !self.is_builder_target(target)
             && helpers::use_host_linker(target)
             && !target.is_msvc()
         {
@@ -1930,8 +1946,8 @@ to download LLVM rather than building it.
     }
 
     /// Checks if the given target is the same as the builder target.
-    fn is_builder_target(&self, target: &TargetSelection) -> bool {
-        &self.config.build == target
+    fn is_builder_target(&self, target: TargetSelection) -> bool {
+        self.config.build == target
     }
 }
 
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 9b23cf1843e..f215c3f6d0b 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -350,4 +350,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "The llvm.ccache option has moved to build.ccache. llvm.ccache is now deprecated.",
     },
+    ChangeInfo {
+        change_id: 137170,
+        severity: ChangeSeverity::Info,
+        summary: "It is now possible to configure `jemalloc` for each target",
+    },
 ];
diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs
index dbfd6f47dc6..34bf6bb7013 100644
--- a/src/bootstrap/src/utils/proc_macro_deps.rs
+++ b/src/bootstrap/src/utils/proc_macro_deps.rs
@@ -6,25 +6,18 @@ pub static CRATES: &[&str] = &[
     "annotate-snippets",
     "anstyle",
     "basic-toml",
-    "block-buffer",
     "bumpalo",
-    "cfg-if",
-    "cpufeatures",
-    "crypto-common",
     "darling",
     "darling_core",
     "derive_builder_core",
-    "digest",
     "fluent-bundle",
     "fluent-langneg",
     "fluent-syntax",
     "fnv",
-    "generic-array",
     "heck",
     "ident_case",
     "intl-memoizer",
     "intl_pluralrules",
-    "libc",
     "log",
     "memchr",
     "mime",
@@ -32,17 +25,12 @@ pub static CRATES: &[&str] = &[
     "minimal-lexical",
     "nom",
     "num-conv",
-    "once_cell",
-    "pest",
-    "pest_generator",
-    "pest_meta",
     "proc-macro2",
     "quote",
     "rinja_parser",
     "rustc-hash",
     "self_cell",
     "serde",
-    "sha2",
     "smallvec",
     "stable_deref_trait",
     "strsim",
@@ -52,15 +40,12 @@ pub static CRATES: &[&str] = &[
     "time-core",
     "tinystr",
     "type-map",
-    "typenum",
-    "ucd-trie",
     "unic-langid",
     "unic-langid-impl",
     "unic-langid-macros",
     "unicase",
     "unicode-ident",
     "unicode-width",
-    "version_check",
     "wasm-bindgen-backend",
     "wasm-bindgen-macro-support",
     "wasm-bindgen-shared",
diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig
index 576f3631cd5..aa33f72268e 100644
--- a/src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig
+++ b/src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig
@@ -7,6 +7,8 @@ CT_ARCH_LOONGARCH=y
 # CT_DEMULTILIB is not set
 CT_ARCH_USE_MMU=y
 CT_ARCH_ARCH="loongarch64"
+CT_TARGET_CFLAGS="-mcmodel=medium"
+CT_TARGET_LDFLAGS="-mcmodel=medium"
 CT_KERNEL_LINUX=y
 CT_LINUX_V_5_19=y
 CT_GLIBC_V_2_36=y
diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig
index 3ab676ed971..3ccbc583c1b 100644
--- a/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig
+++ b/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig
@@ -7,6 +7,8 @@ CT_ARCH_LOONGARCH=y
 # CT_DEMULTILIB is not set
 CT_ARCH_USE_MMU=y
 CT_ARCH_ARCH="loongarch64"
+CT_TARGET_CFLAGS="-mcmodel=medium"
+CT_TARGET_LDFLAGS="-mcmodel=medium"
 CT_KERNEL_LINUX=y
 CT_LINUX_V_5_19=y
 CT_LIBC_MUSL=y
diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh
index 3eb85ab215e..573821c3e59 100755
--- a/src/ci/docker/scripts/rfl-build.sh
+++ b/src/ci/docker/scripts/rfl-build.sh
@@ -2,7 +2,7 @@
 
 set -euo pipefail
 
-LINUX_VERSION=50e57739141b41f731ab31f8380821c7969f9dc4
+LINUX_VERSION=v6.14-rc3
 
 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt
 ../x.py build --stage 2 library rustdoc clippy rustfmt
@@ -28,7 +28,7 @@ rm -rf linux || true
 # Download Linux at a specific commit
 mkdir -p linux
 git -C linux init
-git -C linux remote add origin https://github.com/Darksonn/linux.git
+git -C linux remote add origin https://github.com/Rust-for-Linux/linux.git
 git -C linux fetch --depth 1 origin ${LINUX_VERSION}
 git -C linux checkout FETCH_HEAD
 
diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
index 9fcb16b0fca..dc63e1aa511 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
@@ -75,7 +75,7 @@ impl rustc_driver::Callbacks for MyCallbacks {
             let item = hir_krate.item(id);
             // Use pattern-matching to find a specific node inside the main function.
             if let rustc_hir::ItemKind::Fn(_, _, body_id) = item.kind {
-                let expr = &tcx.hir().body(body_id).value;
+                let expr = &tcx.hir_body(body_id).value;
                 if let rustc_hir::ExprKind::Block(block, _) = expr.kind {
                     if let rustc_hir::StmtKind::Let(let_stmt) = block.stmts[0].kind {
                         if let Some(expr) = let_stmt.init {
diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md
index 04fa5b204dd..04d8e91dcb4 100644
--- a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md
+++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md
@@ -76,6 +76,14 @@ $ BOOTSTRAP_TRACING=CONFIG_HANDLING=TRACE ./x build library --stage 1
 
 [tracing-env-filter]: https://docs.rs/tracing-subscriber/0.3.19/tracing_subscriber/filter/struct.EnvFilter.html
 
+##### FIXME(#96176): specific tracing for `compiler()` vs `compiler_for()`
+
+The additional targets `COMPILER` and `COMPILER_FOR` are used to help trace what
+`builder.compiler()` and `builder.compiler_for()` does. They should be removed
+if [#96176][cleanup-compiler-for] is resolved.
+
+[cleanup-compiler-for]: https://github.com/rust-lang/rust/issues/96176
+
 ### Using `tracing` in bootstrap
 
 Both `tracing::*` macros and the `tracing::instrument` proc-macro attribute need to be gated behind `tracing` feature. Examples:
diff --git a/src/doc/rustc/src/platform-support/loongarch-none.md b/src/doc/rustc/src/platform-support/loongarch-none.md
index 110a7cc3424..bafa85c26e2 100644
--- a/src/doc/rustc/src/platform-support/loongarch-none.md
+++ b/src/doc/rustc/src/platform-support/loongarch-none.md
@@ -32,7 +32,7 @@ By default, code generated with the soft-float target should run on any
 LoongArch64 hardware, with the hard-float target additionally requiring an FPU;
 enabling additional target features may raise this baseline.
 
-Code generated with the targets will use the `small` code model by default.
+Code generated with the targets will use the `medium` code model by default.
 You can change this using the `-C code-model=` option to rustc.
 
 On `loongarch64-unknown-none*`, `extern "C"` uses the [architecture's standard calling convention][lapcs].
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index c593cdcbcd2..c07cc4dc347 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -13,7 +13,7 @@ rinja = { version = "0.3", default-features = false, features = ["config"] }
 base64 = "0.21.7"
 itertools = "0.12"
 indexmap = "2"
-minifier = { version = "0.3.4", default-features = false }
+minifier = { version = "0.3.5", default-features = false }
 pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false }
 regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 3d51ab1967d..e10a74221ae 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -488,7 +488,7 @@ pub(crate) fn build_impl(
             impl_
                 .items
                 .iter()
-                .map(|item| tcx.hir().impl_item(item.id))
+                .map(|item| tcx.hir_impl_item(item.id))
                 .filter(|item| {
                     // Filter out impl items whose corresponding trait item has `doc(hidden)`
                     // not to document such impl items.
@@ -703,7 +703,7 @@ fn build_module_items(
 pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
     if let Some(did) = did.as_local() {
         let hir_id = tcx.local_def_id_to_hir_id(did);
-        rustc_hir_pretty::id_to_string(&tcx.hir(), hir_id)
+        rustc_hir_pretty::id_to_string(&tcx, hir_id)
     } else {
         tcx.rendered_const(did).clone()
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 1d62a93e723..dcc5fd12d81 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1145,14 +1145,14 @@ fn clean_args_from_types_and_body_id<'tcx>(
     types: &[hir::Ty<'tcx>],
     body_id: hir::BodyId,
 ) -> Arguments {
-    let body = cx.tcx.hir().body(body_id);
+    let body = cx.tcx.hir_body(body_id);
 
     Arguments {
         values: types
             .iter()
-            .enumerate()
-            .map(|(i, ty)| Argument {
-                name: name_from_pat(body.params[i].pat),
+            .zip(body.params)
+            .map(|(ty, param)| Argument {
+                name: name_from_pat(param.pat),
                 type_: clean_ty(ty, cx),
                 is_const: false,
             })
@@ -2845,7 +2845,7 @@ fn clean_maybe_renamed_item<'tcx>(
             ItemKind::Trait(_, _, generics, bounds, item_ids) => {
                 let items = item_ids
                     .iter()
-                    .map(|ti| clean_trait_item(cx.tcx.hir().trait_item(ti.id), cx))
+                    .map(|ti| clean_trait_item(cx.tcx.hir_trait_item(ti.id), cx))
                     .collect();
 
                 TraitItem(Box::new(Trait {
@@ -2891,7 +2891,7 @@ fn clean_impl<'tcx>(
     let items = impl_
         .items
         .iter()
-        .map(|ii| clean_impl_item(tcx.hir().impl_item(ii.id), cx))
+        .map(|ii| clean_impl_item(tcx.hir_impl_item(ii.id), cx))
         .collect::<Vec<_>>();
 
     // If this impl block is an implementation of the Deref trait, then we
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 5f7c30a33ab..fc7c4b42047 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -220,12 +220,11 @@ impl ExternalCrate {
             None
         };
         if root.is_local() {
-            tcx.hir()
-                .root_module()
+            tcx.hir_root_module()
                 .item_ids
                 .iter()
                 .filter_map(|&id| {
-                    let item = tcx.hir().item(id);
+                    let item = tcx.hir_item(id);
                     match item.kind {
                         hir::ItemKind::Mod(_) => {
                             as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
@@ -277,12 +276,11 @@ impl ExternalCrate {
         };
 
         if root.is_local() {
-            tcx.hir()
-                .root_module()
+            tcx.hir_root_module()
                 .item_ids
                 .iter()
                 .filter_map(|&id| {
-                    let item = tcx.hir().item(id);
+                    let item = tcx.hir_item(id);
                     match item.kind {
                         hir::ItemKind::Mod(_) => {
                             as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
@@ -2122,9 +2120,8 @@ impl Discriminant {
     /// Will be `None` in the case of cross-crate reexports, and may be
     /// simplified
     pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
-        self.expr.map(|body| {
-            rendered_const(tcx, tcx.hir().body(body), tcx.hir().body_owner_def_id(body))
-        })
+        self.expr
+            .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
     }
     pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
         print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
@@ -2420,7 +2417,7 @@ impl ConstantKind {
             ConstantKind::Path { ref path } => path.to_string(),
             ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
             ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
-                rendered_const(tcx, tcx.hir().body(body), tcx.hir().body_owner_def_id(body))
+                rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
             }
             ConstantKind::Infer { .. } => "_".to_string(),
         }
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 8a7d140bb1a..34656b26ce2 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -1,5 +1,5 @@
 use std::assert_matches::debug_assert_matches;
-use std::fmt::Write as _;
+use std::fmt::{self, Display, Write as _};
 use std::mem;
 use std::sync::LazyLock as Lazy;
 
@@ -24,6 +24,7 @@ use crate::clean::{
     clean_middle_ty, inline,
 };
 use crate::core::DocContext;
+use crate::display::Joined as _;
 
 #[cfg(test)]
 mod tests;
@@ -250,16 +251,20 @@ pub(crate) fn qpath_to_string(p: &hir::QPath<'_>) -> String {
         hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(),
     };
 
-    let mut s = String::new();
-    for (i, seg) in segments.iter().enumerate() {
-        if i > 0 {
-            s.push_str("::");
-        }
-        if seg.ident.name != kw::PathRoot {
-            s.push_str(seg.ident.as_str());
-        }
-    }
-    s
+    fmt::from_fn(|f| {
+        segments
+            .iter()
+            .map(|seg| {
+                fmt::from_fn(|f| {
+                    if seg.ident.name != kw::PathRoot {
+                        write!(f, "{}", seg.ident)?;
+                    }
+                    Ok(())
+                })
+            })
+            .joined("::", f)
+    })
+    .to_string()
 }
 
 pub(crate) fn build_deref_target_impls(
@@ -299,35 +304,49 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
 
     Symbol::intern(&match p.kind {
         // FIXME(never_patterns): does this make sense?
-        PatKind::Wild | PatKind::Err(_) | PatKind::Never | PatKind::Struct(..) => {
+        PatKind::Wild
+        | PatKind::Err(_)
+        | PatKind::Never
+        | PatKind::Struct(..)
+        | PatKind::Range(..) => {
             return kw::Underscore;
         }
         PatKind::Binding(_, _, ident, _) => return ident.name,
+        PatKind::Box(p) | PatKind::Ref(p, _) | PatKind::Guard(p, _) => return name_from_pat(p),
         PatKind::TupleStruct(ref p, ..)
         | PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref p), .. }) => qpath_to_string(p),
         PatKind::Or(pats) => {
-            pats.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(" | ")
+            fmt::from_fn(|f| pats.iter().map(|p| name_from_pat(p)).joined(" | ", f)).to_string()
+        }
+        PatKind::Tuple(elts, _) => {
+            format!("({})", fmt::from_fn(|f| elts.iter().map(|p| name_from_pat(p)).joined(", ", f)))
         }
-        PatKind::Tuple(elts, _) => format!(
-            "({})",
-            elts.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(", ")
-        ),
-        PatKind::Box(p) => return name_from_pat(p),
         PatKind::Deref(p) => format!("deref!({})", name_from_pat(p)),
-        PatKind::Ref(p, _) => return name_from_pat(p),
         PatKind::Expr(..) => {
             warn!(
                 "tried to get argument name from PatKind::Expr, which is silly in function arguments"
             );
             return Symbol::intern("()");
         }
-        PatKind::Guard(p, _) => return name_from_pat(p),
-        PatKind::Range(..) => return kw::Underscore,
-        PatKind::Slice(begin, ref mid, end) => {
-            let begin = begin.iter().map(|p| name_from_pat(p).to_string());
-            let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(p))).into_iter();
-            let end = end.iter().map(|p| name_from_pat(p).to_string());
-            format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", "))
+        PatKind::Slice(begin, mid, end) => {
+            fn print_pat<'a>(pat: &'a Pat<'a>, wild: bool) -> impl Display + 'a {
+                fmt::from_fn(move |f| {
+                    if wild {
+                        f.write_str("..")?;
+                    }
+                    name_from_pat(pat).fmt(f)
+                })
+            }
+
+            format!(
+                "[{}]",
+                fmt::from_fn(|f| {
+                    let begin = begin.iter().map(|p| print_pat(p, false));
+                    let mid = mid.map(|p| print_pat(p, true));
+                    let end = end.iter().map(|p| print_pat(p, false));
+                    begin.chain(mid).chain(end).joined(", ", f)
+                })
+            )
         }
     })
 }
@@ -336,7 +355,7 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
     match n.kind() {
         ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args: _ }) => {
             let s = if let Some(def) = def.as_local() {
-                rendered_const(cx.tcx, cx.tcx.hir().body_owned_by(def), def)
+                rendered_const(cx.tcx, cx.tcx.hir_body_owned_by(def), def)
             } else {
                 inline::print_inlined_const(cx.tcx, def)
             };
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 5c146da03ac..757a2a6e0dd 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -304,8 +304,7 @@ pub(crate) fn create_config(
                     return tcx.typeck(typeck_root_def_id);
                 }
 
-                let hir = tcx.hir();
-                let body = hir.body_owned_by(def_id);
+                let body = tcx.hir_body_owned_by(def_id);
                 debug!("visiting body for {def_id:?}");
                 EmitIgnoredResolutionErrors::new(tcx).visit_body(body);
                 (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id)
@@ -335,14 +334,14 @@ pub(crate) fn run_global_ctxt(
 
     // NOTE: These are copy/pasted from typeck/lib.rs and should be kept in sync with those changes.
     let _ = tcx.sess.time("wf_checking", || {
-        tcx.hir().try_par_for_each_module(|module| tcx.ensure_ok().check_mod_type_wf(module))
+        tcx.try_par_hir_for_each_module(|module| tcx.ensure_ok().check_mod_type_wf(module))
     });
 
     tcx.dcx().abort_if_errors();
 
     tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx));
     tcx.sess.time("check_mod_attrs", || {
-        tcx.hir().for_each_module(|module| tcx.ensure_ok().check_mod_attrs(module))
+        tcx.hir_for_each_module(|module| tcx.ensure_ok().check_mod_attrs(module))
     });
     rustc_passes::stability::check_unused_or_stable_features(tcx);
 
@@ -378,7 +377,7 @@ pub(crate) fn run_global_ctxt(
         ctxt.external_traits.insert(sized_trait_did, sized_trait);
     }
 
-    debug!("crate: {:?}", tcx.hir().krate());
+    debug!("crate: {:?}", tcx.hir_crate(()));
 
     let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
 
@@ -464,10 +463,10 @@ impl<'tcx> EmitIgnoredResolutionErrors<'tcx> {
 impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
         // We need to recurse into nested closures,
         // since those will fallback to the parent for type checking.
-        self.tcx.hir()
+        self.tcx
     }
 
     fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs
index d89caabefe3..4792bc525a5 100644
--- a/src/librustdoc/doctest/make.rs
+++ b/src/librustdoc/doctest/make.rs
@@ -1,6 +1,7 @@
 //! Logic for transforming the raw code given by the user into something actually
 //! runnable, e.g. by adding a `main` function if it doesn't already exist.
 
+use std::fmt::{self, Write as _};
 use std::io;
 use std::sync::Arc;
 
@@ -17,6 +18,7 @@ use rustc_span::symbol::sym;
 use tracing::debug;
 
 use super::GlobalTestOptions;
+use crate::display::Joined as _;
 use crate::html::markdown::LangString;
 
 /// This struct contains information about the doctest itself which is then used to generate
@@ -232,13 +234,15 @@ impl DocTestBuilder {
 
             // add extra 4 spaces for each line to offset the code block
             if opts.insert_indent_space {
-                prog.push_str(
-                    &everything_else
+                write!(
+                    prog,
+                    "{}",
+                    fmt::from_fn(|f| everything_else
                         .lines()
-                        .map(|line| format!("    {}", line))
-                        .collect::<Vec<String>>()
-                        .join("\n"),
-                );
+                        .map(|line| fmt::from_fn(move |f| write!(f, "    {line}")))
+                        .joined("\n", f))
+                )
+                .unwrap();
             } else {
                 prog.push_str(everything_else);
             };
diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs
index c4956bfd2b4..1ac3c040b59 100644
--- a/src/librustdoc/doctest/rust.rs
+++ b/src/librustdoc/doctest/rust.rs
@@ -81,7 +81,7 @@ impl<'tcx> HirCollector<'tcx> {
     pub fn collect_crate(mut self) -> Vec<ScrapedDocTest> {
         let tcx = self.tcx;
         self.visit_testable("".to_string(), CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), |this| {
-            tcx.hir().walk_toplevel_module(this)
+            tcx.hir_walk_toplevel_module(this)
         });
         self.collector.tests
     }
@@ -147,14 +147,14 @@ impl HirCollector<'_> {
 impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'_>) {
         let name = match &item.kind {
             hir::ItemKind::Impl(impl_) => {
-                rustc_hir_pretty::id_to_string(&self.tcx.hir(), impl_.self_ty.hir_id)
+                rustc_hir_pretty::id_to_string(&self.tcx, impl_.self_ty.hir_id)
             }
             _ => item.ident.to_string(),
         };
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index d2d7415261b..f3201147039 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -2,7 +2,6 @@ use std::cmp::Ordering;
 use std::fmt;
 use std::fmt::Display;
 
-use itertools::Itertools;
 use rinja::Template;
 use rustc_abi::VariantIdx;
 use rustc_data_structures::captures::Captures;
@@ -514,11 +513,7 @@ fn item_module(w: &mut String, cx: &Context<'_>, item: &clean::Item, items: &[cl
                         class = myitem.type_(),
                         unsafety_flag = unsafety_flag,
                         href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
-                        title = [myitem.type_().to_string(), full_path(cx, myitem)]
-                            .iter()
-                            .filter_map(|s| if !s.is_empty() { Some(s.as_str()) } else { None })
-                            .collect::<Vec<_>>()
-                            .join(" "),
+                        title = format_args!("{} {}", myitem.type_(), full_path(cx, myitem)),
                     ),
                 );
             }
@@ -915,7 +910,7 @@ fn item_trait(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                 w,
                 format_args!(
                     "<div class=\"stab must_implement\">At least one of the `{}` methods is required.</div>",
-                    list.iter().join("`, `")
+                    fmt::from_fn(|f| list.iter().joined("`, `", f))
                 ),
             );
         }
@@ -1168,17 +1163,18 @@ fn item_trait(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         js_src_path.extend(cx.current.iter().copied());
         js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), it.name.unwrap()));
     }
-    let extern_crates = extern_crates
-        .into_iter()
-        .map(|cnum| tcx.crate_name(cnum).to_string())
-        .collect::<Vec<_>>()
-        .join(",");
-    let (extern_before, extern_after) =
-        if extern_crates.is_empty() { ("", "") } else { (" data-ignore-extern-crates=\"", "\"") };
+    let extern_crates = fmt::from_fn(|f| {
+        if !extern_crates.is_empty() {
+            f.write_str(" data-ignore-extern-crates=\"")?;
+            extern_crates.iter().map(|&cnum| tcx.crate_name(cnum)).joined(",", f)?;
+            f.write_str("\"")?;
+        }
+        Ok(())
+    });
     write_str(
         w,
         format_args!(
-            "<script src=\"{src}\"{extern_before}{extern_crates}{extern_after} async></script>",
+            "<script src=\"{src}\"{extern_crates} async></script>",
             src = js_src_path.finish()
         ),
     );
@@ -1400,7 +1396,7 @@ fn item_type_alias(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean
             .collect();
         js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied());
         js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap()));
-        let self_path = self_fqp.iter().map(Symbol::as_str).collect::<Vec<&str>>().join("::");
+        let self_path = fmt::from_fn(|f| self_fqp.iter().joined("::", f));
         write_str(
             w,
             format_args!(
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index a15ac155123..658d5965b3d 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -51,7 +51,7 @@ pub(crate) fn collect_spans_and_sources(
         let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() };
 
         if generate_link_to_definition {
-            tcx.hir().walk_toplevel_module(&mut visitor);
+            tcx.hir_walk_toplevel_module(&mut visitor);
         }
         let sources = sources::collect_local_sources(tcx, src_root, krate);
         (sources, visitor.matches)
@@ -173,18 +173,18 @@ impl SpanMapVisitor<'_> {
     }
 
     fn infer_id(&mut self, hir_id: HirId, expr_hir_id: Option<HirId>, span: Span) {
-        let hir = self.tcx.hir();
-        let body_id = hir.enclosing_body_owner(hir_id);
+        let tcx = self.tcx;
+        let body_id = tcx.hir_enclosing_body_owner(hir_id);
         // FIXME: this is showing error messages for parts of the code that are not
         // compiled (because of cfg)!
         //
         // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
-        let typeck_results = self.tcx.typeck_body(hir.body_owned_by(body_id).id());
+        let typeck_results = tcx.typeck_body(tcx.hir_body_owned_by(body_id).id());
         // Interestingly enough, for method calls, we need the whole expression whereas for static
         // method/function calls, we need the call expression specifically.
         if let Some(def_id) = typeck_results.type_dependent_def_id(expr_hir_id.unwrap_or(hir_id)) {
             let link = if def_id.as_local().is_some() {
-                LinkFromSrc::Local(rustc_span(def_id, self.tcx))
+                LinkFromSrc::Local(rustc_span(def_id, tcx))
             } else {
                 LinkFromSrc::External(def_id)
             };
@@ -221,8 +221,8 @@ impl SpanMapVisitor<'_> {
 impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_path(&mut self, path: &rustc_hir::Path<'tcx>, _id: HirId) {
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index fcee2960979..9606ba76991 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -846,7 +846,7 @@ fn convert_static(
         is_unsafe: safety.is_unsafe(),
         expr: stat
             .expr
-            .map(|e| rendered_const(tcx, tcx.hir().body(e), tcx.hir().body_owner_def_id(e)))
+            .map(|e| rendered_const(tcx, tcx.hir_body(e), tcx.hir_body_owner_def_id(e)))
             .unwrap_or_default(),
     }
 }
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 135aa799060..45b8dafa907 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -232,7 +232,7 @@ impl DocVisitor<'_> for CoverageCalculator<'_, '_> {
                     .item_id
                     .as_def_id()
                     .and_then(|def_id| self.ctx.tcx.opt_parent(def_id))
-                    .and_then(|def_id| self.ctx.tcx.hir().get_if_local(def_id))
+                    .and_then(|def_id| self.ctx.tcx.hir_get_if_local(def_id))
                     .map(|node| {
                         matches!(
                             node,
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index 599671bd4d4..a36dcb0d30e 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -123,8 +123,8 @@ where
 {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx().hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx()
     }
 
     fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
@@ -135,8 +135,7 @@ where
         // If we visit an item that contains an expression outside a function body,
         // then we need to exit before calling typeck (which will panic). See
         // test/run-make/rustdoc-scrape-examples-invalid-expr for an example.
-        let hir = tcx.hir();
-        if hir.maybe_body_owned_by(ex.hir_id.owner.def_id).is_none() {
+        if tcx.hir_maybe_body_owned_by(ex.hir_id.owner.def_id).is_none() {
             return;
         }
 
@@ -302,7 +301,7 @@ pub(crate) fn run(
         // Run call-finder on all items
         let mut calls = FxIndexMap::default();
         let mut finder = FindCalls { calls: &mut calls, cx, target_crates, bin_crate };
-        tcx.hir().visit_all_item_likes_in_crate(&mut finder);
+        tcx.hir_visit_all_item_likes_in_crate(&mut finder);
 
         // The visitor might have found a type error, which we need to
         // promote to a fatal error
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index e4628e4f837..f606a3d8a92 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -96,7 +96,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         let om = Module::new(
             cx.tcx.crate_name(LOCAL_CRATE),
             CRATE_DEF_ID,
-            cx.tcx.hir().root_module().spans.inner_span,
+            cx.tcx.hir_root_module().spans.inner_span,
             None,
             None,
         );
@@ -119,7 +119,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     }
 
     pub(crate) fn visit(mut self) -> Module<'tcx> {
-        let root_module = self.cx.tcx.hir().root_module();
+        let root_module = self.cx.tcx.hir_root_module();
         self.visit_mod_contents(CRATE_DEF_ID, root_module);
 
         let mut top_level_module = self.modules.pop().unwrap();
@@ -193,13 +193,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         // Reimplementation of `walk_mod` because we need to do it in two passes (explanations in
         // the second loop):
         for &i in m.item_ids {
-            let item = self.cx.tcx.hir().item(i);
+            let item = self.cx.tcx.hir_item(i);
             if !matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
                 self.visit_item(item);
             }
         }
         for &i in m.item_ids {
-            let item = self.cx.tcx.hir().item(i);
+            let item = self.cx.tcx.hir_item(i);
             // To match the way import precedence works, visit glob imports last.
             // Later passes in rustdoc will de-duplicate by name and kind, so if glob-
             // imported items appear last, then they'll be the ones that get discarded.
@@ -315,7 +315,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             Node::Item(&hir::Item { kind: hir::ItemKind::Mod(m), .. }) if glob => {
                 let prev = mem::replace(&mut self.inlining, true);
                 for &i in m.item_ids {
-                    let i = tcx.hir().item(i);
+                    let i = tcx.hir_item(i);
                     self.visit_item_inner(i, None, Some(def_id));
                 }
                 self.inlining = prev;
@@ -433,7 +433,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         match item.kind {
             hir::ItemKind::ForeignMod { items, .. } => {
                 for item in items {
-                    let item = tcx.hir().foreign_item(item.id);
+                    let item = tcx.hir_foreign_item(item.id);
                     self.visit_foreign_item_inner(item, None);
                 }
             }
@@ -563,8 +563,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
 impl<'tcx> Visitor<'tcx> for RustdocVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 
     fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 7e8c93c87c611f21d9bd95100563392f4c18bfe
+Subproject 92e80685d0d5dcea3ccf321995c43b72338639c
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index f519a65fc27..aff40fa846b 100644
--- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -338,7 +338,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
             return;
         }
 
-        let items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id));
+        let items = module.item_ids.iter().map(|&id| cx.tcx.hir_item(id));
 
         // Iterates over the items within a module.
         //
diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
index eeaa3de3725..013819b0da8 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -60,12 +60,12 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
                 // XXXkhuey maybe we should?
                 return;
             },
-            CoroutineSource::Block => cx.tcx.hir().body(*body_id).value,
+            CoroutineSource::Block => cx.tcx.hir_body(*body_id).value,
             CoroutineSource::Closure => {
                 // Like `async fn`, async closures are wrapped in an additional block
                 // to move all of the closure's arguments into the future.
 
-                let async_closure_body = cx.tcx.hir().body(*body_id).value;
+                let async_closure_body = cx.tcx.hir_body(*body_id).value;
                 let ExprKind::Block(block, _) = async_closure_body.kind else {
                     return;
                 };
diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
index 152e6ec70a1..a667649f734 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
@@ -22,7 +22,7 @@ pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool {
 
 pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
     if let ItemKind::Fn { body: eid, .. } = item.kind {
-        is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
+        is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value)
     } else {
         true
     }
@@ -30,7 +30,7 @@ pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
 
 pub(super) fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool {
     match item.kind {
-        ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value),
+        ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value),
         _ => false,
     }
 }
@@ -39,7 +39,7 @@ pub(super) fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> b
     match item.kind {
         TraitItemKind::Fn(_, TraitFn::Required(_)) => true,
         TraitItemKind::Fn(_, TraitFn::Provided(eid)) => {
-            is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
+            is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value)
         },
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index f8c30d1c881..f30f16997d7 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -452,7 +452,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: &Msrv, expr: &Expr<'_>) -> Opti
                 })
         },
         ExprKind::Closure(closure) => {
-            let body = cx.tcx.hir().body(closure.body);
+            let body = cx.tcx.hir_body(closure.body);
             let params = body
                 .params
                 .iter()
diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
index 8276e53648c..1279be34ed8 100644
--- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
+++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
@@ -118,7 +118,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
             let is_read_in_closure_arg = args.iter().any(|arg| {
                 if let ExprKind::Closure(closure) = arg.kind
                     // To keep things simple, we only check the first param to see if its read.
-                    && let Body { params: [param, ..], value } = cx.tcx.hir().body(closure.body)
+                    && let Body { params: [param, ..], value } = cx.tcx.hir_body(closure.body)
                 {
                     !has_no_read_access(cx, param.hir_id, *value)
                 } else {
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 772268e7899..784214c29af 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -52,11 +52,10 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
 
 impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback {
     fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) {
-        let hir = cx.tcx.hir();
         // NOTE: this is different from `clippy_utils::is_inside_always_const_context`.
         // Inline const supports type inference.
         let is_parent_const = matches!(
-            hir.body_const_context(hir.body_owner_def_id(body.id())),
+            cx.tcx.hir_body_const_context(cx.tcx.hir_body_owner_def_id(body.id())),
             Some(ConstContext::Const { inline: false } | ConstContext::Static(_))
         );
         let mut visitor = NumericFallbackVisitor::new(cx, is_parent_const);
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index 9569081ad08..bb445e0155f 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -197,7 +197,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
             && let impl_item_hir = child.id.hir_id()
             && let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir)
             && let ImplItemKind::Fn(_, b) = &impl_item.kind
-            && let Body { value: func_expr, .. } = cx.tcx.hir().body(*b)
+            && let Body { value: func_expr, .. } = cx.tcx.hir_body(*b)
             && let &ty::Adt(adt_def, args) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
             && let attrs = cx.tcx.hir().attrs(item.hir_id())
             && !attrs.iter().any(|attr| attr.doc_str().is_some())
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 91ddbb44ff8..db3e6034c5b 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -437,8 +437,8 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
         walk_expr(self, expr)
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
index 8e2af6bf14a..d1ffbb6ffe2 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -68,7 +68,7 @@ pub fn check(
         } else if let Some(body_id) = body_id
             && let Some(future) = cx.tcx.lang_items().future_trait()
             && let typeck = cx.tcx.typeck_body(body_id)
-            && let body = cx.tcx.hir().body(body_id)
+            && let body = cx.tcx.hir_body(body_id)
             && let ret_ty = typeck.expr_ty(body.value)
             && implements_trait_with_env(
                 cx.tcx,
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 42e1f7fd950..93c2b7a2d18 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -597,7 +597,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
                         if !(is_entrypoint_fn(cx, item.owner_id.to_def_id())
                             || item.span.in_external_macro(cx.tcx.sess.source_map()))
                         {
-                            let body = cx.tcx.hir().body(body_id);
+                            let body = cx.tcx.hir_body(body_id);
 
                             let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
                             missing_headers::check(
@@ -649,7 +649,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
                     && !impl_item.span.in_external_macro(cx.tcx.sess.source_map())
                     && !is_trait_impl_item(cx, impl_item.hir_id())
                 {
-                    let body = cx.tcx.hir().body(body_id);
+                    let body = cx.tcx.hir_body(body_id);
 
                     let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(impl_item.owner_id), body.value);
                     missing_headers::check(
@@ -1079,8 +1079,8 @@ impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> {
     // Panics in const blocks will cause compilation to fail.
     fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/empty_drop.rs b/src/tools/clippy/clippy_lints/src/empty_drop.rs
index 10a84b1b2ff..d557a36c7ac 100644
--- a/src/tools/clippy/clippy_lints/src/empty_drop.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_drop.rs
@@ -44,7 +44,7 @@ impl LateLintPass<'_> for EmptyDrop {
             && let impl_item_hir = child.id.hir_id()
             && let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir)
             && let ImplItemKind::Fn(_, b) = &impl_item.kind
-            && let Body { value: func_expr, .. } = cx.tcx.hir().body(*b)
+            && let Body { value: func_expr, .. } = cx.tcx.hir_body(*b)
             && let func_expr = peel_blocks(func_expr)
             && let ExprKind::Block(block, _) = func_expr.kind
             && block.stmts.is_empty()
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index a090a987d4f..2e1f8ac615a 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -41,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
         if let ItemKind::Enum(def, _) = &item.kind {
             for var in def.variants {
                 if let Some(anon_const) = &var.disr_expr {
-                    let def_id = cx.tcx.hir().body_owner_def_id(anon_const.body);
+                    let def_id = cx.tcx.hir_body_owner_def_id(anon_const.body);
                     let mut ty = cx.tcx.type_of(def_id.to_def_id()).instantiate_identity();
                     let constant = cx
                         .tcx
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index ae3acc1c4b1..d1782d582f4 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -97,7 +97,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
         && matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
         && !expr.span.from_expansion()
     {
-        cx.tcx.hir().body(c.body)
+        cx.tcx.hir_body(c.body)
     } else {
         return;
     };
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
index 5d93aceb33f..6a217b6182c 100644
--- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -241,13 +241,13 @@ impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> {
         }
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
 fn is_empty_body(cx: &LateContext<'_>, body: BodyId) -> bool {
-    matches!(cx.tcx.hir().body(body).value.kind, ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none())
+    matches!(cx.tcx.hir_body(body).value.kind, ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none())
 }
 
 impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index f822432cce6..f67d38d932b 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -98,10 +98,10 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl
 
     for impl_item in impl_items {
         if impl_item.ident.name == sym::from
-            && let ImplItemKind::Fn(_, body_id) = cx.tcx.hir().impl_item(impl_item.id).kind
+            && let ImplItemKind::Fn(_, body_id) = cx.tcx.hir_impl_item(impl_item.id).kind
         {
             // check the body for `begin_panic` or `unwrap`
-            let body = cx.tcx.hir().body(body_id);
+            let body = cx.tcx.hir_body(body_id);
             let mut fpu = FindPanicUnwrap {
                 lcx: cx,
                 typeck_results: cx.tcx.typeck(impl_item.id.owner_id.def_id),
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index 5619cb0ab1b..ff75fcf2b41 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -262,7 +262,7 @@ fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Optio
         && let Some(name) = cx.tcx.get_diagnostic_name(did)
         && matches!(name, sym::Debug | sym::Display)
     {
-        let body = cx.tcx.hir().body(body_id);
+        let body = cx.tcx.hir_body(body_id);
         let formatter_name = body
             .params
             .get(1)
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 9a73d0c0993..41bf6e81916 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -134,8 +134,8 @@ impl<'tcx> Visitor<'tcx> for SelfFinder<'_, 'tcx> {
     type Result = ControlFlow<()>;
     type NestedFilter = OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 
     fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) -> Self::Result {
@@ -175,11 +175,11 @@ fn convert_to_from(
         // bad suggestion/fix.
         return None;
     }
-    let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
+    let impl_item = cx.tcx.hir_impl_item(impl_item_ref.id);
     let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else {
         return None;
     };
-    let body = cx.tcx.hir().body(body_id);
+    let body = cx.tcx.hir_body(body_id);
     let [input] = body.params else { return None };
     let PatKind::Binding(.., self_ident, None) = input.pat.kind else {
         return None;
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
index 752dbc0db4d..cb83b1395d2 100644
--- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -39,7 +39,7 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_
 
 pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
     if let FnKind::ItemFn(_, generics, _) = kind
-        && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
+        && cx.tcx.visibility(cx.tcx.hir_body_owner_def_id(body.id())).is_public()
         && !is_in_test(cx.tcx, hir_id)
     {
         for param in generics.params {
@@ -56,8 +56,8 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
         && let hir::ItemKind::Impl(impl_) = item.kind
         && let hir::Impl { of_trait, .. } = *impl_
         && of_trait.is_none()
-        && let body = cx.tcx.hir().body(body_id)
-        && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
+        && let body = cx.tcx.hir_body(body_id)
+        && cx.tcx.visibility(cx.tcx.hir_body_owner_def_id(body.id())).is_public()
         && !is_in_test(cx.tcx, impl_item.hir_id())
     {
         for param in impl_item.generics.params {
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index e480805cac2..e6e3ea59a9f 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -37,7 +37,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
             check_must_use_candidate(
                 cx,
                 sig.decl,
-                cx.tcx.hir().body(*body_id),
+                cx.tcx.hir_body(*body_id),
                 item.span,
                 item.owner_id,
                 item.span.with_hi(sig.decl.output.span().hi()),
@@ -59,7 +59,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
             check_must_use_candidate(
                 cx,
                 sig.decl,
-                cx.tcx.hir().body(*body_id),
+                cx.tcx.hir_body(*body_id),
                 item.span,
                 item.owner_id,
                 item.span.with_hi(sig.decl.output.span().hi()),
@@ -79,7 +79,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
         } else if let hir::TraitFn::Provided(eid) = *eid {
-            let body = cx.tcx.hir().body(eid);
+            let body = cx.tcx.hir_body(eid);
             if attr.is_none() && is_public && !is_proc_macro(attrs) {
                 check_must_use_candidate(
                     cx,
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 8a74951ef63..906bbd006d4 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -30,7 +30,7 @@ pub(super) fn check_fn<'tcx>(
 
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
-        let body = cx.tcx.hir().body(eid);
+        let body = cx.tcx.hir_body(eid);
         check_raw_ptr(cx, sig.header.safety(), sig.decl, body, item.owner_id.def_id);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
index ac2e866e4ff..5ad83f886e2 100644
--- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
@@ -22,7 +22,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored
         && let Some(did) = trait_item_def_id_of_impl(items, item.owner_id)
         && !is_from_ignored_trait(trait_ref, ignored_traits)
     {
-        let mut param_idents_iter = cx.tcx.hir().body_param_names(body_id);
+        let mut param_idents_iter = cx.tcx.hir_body_param_names(body_id);
         let mut default_param_idents_iter = cx.tcx.fn_arg_names(did).iter().copied();
 
         let renames = RenamedFnArgs::new(&mut default_param_idents_iter, &mut param_idents_iter);
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 47a5c19215b..d2545e57652 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                     });
 
                     let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
-                    for item in impl_.items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
+                    for item in impl_.items.iter().map(|item| cx.tcx.hir_impl_item(item.id)) {
                         ctr_vis.visit_impl_item(item);
                     }
 
@@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                 body: body_id,
                 ..
             } => {
-                let body = cx.tcx.hir().body(body_id);
+                let body = cx.tcx.hir_body(body_id);
 
                 for ty in sig.decl.inputs {
                     let mut vis = ImplicitHasherTypeVisitor::new(cx);
@@ -363,7 +363,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
         walk_expr(self, e);
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 15650c4f732..deac51ab4c4 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -223,8 +223,8 @@ struct SliceIndexLintingVisitor<'a, 'tcx> {
 impl<'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index d3aade31f14..3cb47d8ef91 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -159,7 +159,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
             }
             if method.ident.name.as_str() == "flat_map" && args.len() == 1 {
                 if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
-                    let body = cx.tcx.hir().body(body);
+                    let body = cx.tcx.hir_body(body);
                     return is_infinite(cx, body.value);
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
index f5ad79a0027..021d43cefdd 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
@@ -59,7 +59,7 @@ impl LateLintPass<'_> for ItemsAfterStatements {
                 .iter()
                 .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)))
                 .filter_map(|stmt| match stmt.kind {
-                    StmtKind::Item(id) => Some(cx.tcx.hir().item(id)),
+                    StmtKind::Item(id) => Some(cx.tcx.hir_item(id)),
                     _ => None,
                 })
                 // Ignore macros since they can only see previously defined locals.
diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
index 1ac549b74ac..9df044f25eb 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
@@ -58,7 +58,7 @@ fn cfg_test_module<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
 
 impl LateLintPass<'_> for ItemsAfterTestModule {
     fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) {
-        let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id));
+        let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir_item(id));
 
         let Some((mod_pos, test_mod)) = items.by_ref().enumerate().find(|(_, item)| cfg_test_module(cx, item)) else {
             return;
@@ -91,7 +91,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
                 "items after a test module",
                 |diag| {
                     if let Some(prev) = mod_pos.checked_sub(1)
-                        && let prev = cx.tcx.hir().item(module.item_ids[prev])
+                        && let prev = cx.tcx.hir_item(module.item_ids[prev])
                         && let items_span = last.span.with_lo(test_mod.span.hi())
                         && let Some(items) = items_span.get_source_text(cx)
                     {
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 238f66d6675..173232c511a 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -142,7 +142,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
             })
             && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| {
                 if item.ident.name.as_str() == "IntoIter" {
-                    Some(cx.tcx.hir().impl_item(item.id).expect_type().span)
+                    Some(cx.tcx.hir_impl_item(item.id).expect_type().span)
                 } else {
                     None
                 }
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 26bea8d633a..98ba52f1270 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -316,7 +316,7 @@ enum LenOutput {
 
 fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
     if let ty::Alias(_, alias_ty) = ty.kind()
-        && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir().get_if_local(alias_ty.def_id)
+        && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir_get_if_local(alias_ty.def_id)
         && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin
         && let [GenericBound::Trait(trait_ref)] = &opaque.bounds
         && let Some(segment) = trait_ref.trait_ref.path.segments.last()
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 860c0584acc..f08812017b9 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -19,8 +19,8 @@ use rustc_hir::{
     WherePredicateKind, lang_items,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter as middle_nested_filter;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
@@ -275,7 +275,7 @@ fn could_use_elision<'tcx>(
     }
 
     if let Some(body_id) = body {
-        let body = cx.tcx.hir().body(body_id);
+        let body = cx.tcx.hir_body(body_id);
 
         let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
         if non_elidable_self_type(cx, func, first_ident, msrv) {
@@ -582,7 +582,7 @@ impl<'tcx, F> Visitor<'tcx> for LifetimeChecker<'_, 'tcx, F>
 where
     F: NestedFilter<'tcx>,
 {
-    type Map = Map<'tcx>;
+    type MaybeTyCtxt = TyCtxt<'tcx>;
     type NestedFilter = F;
 
     // for lifetimes as parameters of generics
@@ -628,8 +628,8 @@ where
         self.lifetime_elision_impossible = false;
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
index 8206c75927b..f022598651b 100644
--- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
@@ -101,7 +101,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo
                 ExprKind::Closure(Closure { body, .. }) => {
                     if let Body {
                         params: [param], value, ..
-                    } = cx.tcx.hir().body(*body)
+                    } = cx.tcx.hir_body(*body)
                         && let ExprKind::MethodCall(method, receiver, [], _) = value.kind
                         && path_to_local_id(receiver, param.pat.hir_id)
                         && let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 2e6442156ef..e98c3c9698b 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -370,7 +370,7 @@ impl<'tcx> Visitor<'tcx> for VarVisitor<'_, 'tcx> {
                 }
             },
             ExprKind::Closure(&Closure { body, .. }) => {
-                let body = self.cx.tcx.hir().body(body);
+                let body = self.cx.tcx.hir_body(body);
                 self.visit_expr(body.value);
             },
             _ => walk_expr(self, expr),
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 51fde5288ab..a5185d38e7c 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -240,8 +240,8 @@ impl<'tcx> Visitor<'tcx> for InitializeVisitor<'_, 'tcx> {
         }
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index b7e37c1a876..6000ff7a360 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -245,8 +245,8 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
     impl<'tcx> Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
         type NestedFilter = OnlyBodies;
         type Result = ControlFlow<()>;
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.cx.tcx.hir()
+        fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+            self.cx.tcx
         }
 
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result {
@@ -288,8 +288,8 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
     }
     impl<'tcx> Visitor<'tcx> for NestedLoopVisitor<'_, '_, 'tcx> {
         type NestedFilter = OnlyBodies;
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.cx.tcx.hir()
+        fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+            self.cx.tcx
         }
 
         fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
@@ -351,7 +351,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
             loop_id: loop_expr.hir_id,
             after_loop: false,
         };
-        v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value)
+        v.visit_expr(cx.tcx.hir_body(cx.enclosing_body.unwrap()).value)
             .is_break()
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 9f3b0957eab..6f3a7d8cccc 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -168,7 +168,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>)
         && let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) =
             kind
     {
-        return Some(cx.tcx.hir().body(body));
+        return Some(cx.tcx.hir_body(body));
     }
 
     None
diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
index 052e6502da9..2a5aa12d126 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
             && exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2
             && !expr.span.in_external_macro(cx.sess().source_map())
             && (
-                is_not_const(cx.tcx, cx.tcx.hir().enclosing_body_owner(expr.hir_id).into())
+                is_not_const(cx.tcx, cx.tcx.hir_enclosing_body_owner(expr.hir_id).into())
                     || self.msrv.meets(msrvs::CONST_FLOAT_CLASSIFY)
             )
             && let [first, second, const_1, const_2] = exprs
diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
index 5c40c945c69..e4360518b66 100644
--- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
@@ -191,7 +191,7 @@ fn check_arms(cx: &LateContext<'_>, none_arm: &Arm<'_>, some_arm: &Arm<'_>) -> b
 fn returns_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match expr.kind {
         ExprKind::Path(_) => clippy_utils::is_path_diagnostic_item(cx, expr, sym::default_fn),
-        ExprKind::Closure(cl) => is_empty_slice(cx, cx.tcx.hir().body(cl.body).value),
+        ExprKind::Closure(cl) => is_empty_slice(cx, cx.tcx.hir_body(cl.body).value),
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 708980ac503..0a4e756096e 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -92,7 +92,7 @@ fn check_into_iter(
         && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr)
         && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = target_expr.kind
         && let hir::ExprKind::Closure(closure) = closure_expr.kind
-        && let filter_body = cx.tcx.hir().body(closure.body)
+        && let filter_body = cx.tcx.hir_body(closure.body)
         && let [filter_params] = filter_body.params
     {
         if match_map_type(cx, left_expr) {
@@ -139,7 +139,7 @@ fn check_iter(
         && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr)
         && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind
         && let hir::ExprKind::Closure(closure) = closure_expr.kind
-        && let filter_body = cx.tcx.hir().body(closure.body)
+        && let filter_body = cx.tcx.hir_body(closure.body)
         && let [filter_params] = filter_body.params
     {
         match filter_params.pat.kind {
@@ -198,7 +198,7 @@ fn check_to_owned(
         && SpanlessEq::new(cx).eq_expr(left_expr, str_expr)
         && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind
         && let hir::ExprKind::Closure(closure) = closure_expr.kind
-        && let filter_body = cx.tcx.hir().body(closure.body)
+        && let filter_body = cx.tcx.hir_body(closure.body)
         && let [filter_params] = filter_body.params
     {
         if let hir::PatKind::Ref(pat, _) = filter_params.pat.kind {
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 3221a04d2d0..56aead85e7c 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -163,7 +163,7 @@ fn unit_closure<'tcx>(
     expr: &hir::Expr<'_>,
 ) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> {
     if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = expr.kind
-        && let body = cx.tcx.hir().body(body)
+        && let body = cx.tcx.hir_body(body)
         && let body_expr = &body.value
         && fn_decl.inputs.len() == 1
         && is_unit_expression(cx, body_expr)
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index 91a5de16e96..1e9b29f567f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -163,7 +163,7 @@ impl BindInsteadOfMap {
 
         match arg.kind {
             hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => {
-                let closure_body = cx.tcx.hir().body(body);
+                let closure_body = cx.tcx.hir_body(body);
                 let closure_expr = peel_blocks(closure_body.value);
 
                 if self.lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
index 687272e550b..0498f317442 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
@@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
     filter_arg: &'tcx Expr<'_>,
 ) {
     if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind
-        && let body = cx.tcx.hir().body(body)
+        && let body = cx.tcx.hir_body(body)
         && let [param] = body.params
         && let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind
         && let ExprKind::Binary(ref op, l, r) = body.value.kind
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index c1653b65e98..5b9df6c2bfd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -22,7 +22,7 @@ fn is_method(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol) -> bool
         ExprKind::Path(QPath::Resolved(_, segments)) => segments.segments.last().unwrap().ident.name == method_name,
         ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name,
         ExprKind::Closure(Closure { body, .. }) => {
-            let body = cx.tcx.hir().body(*body);
+            let body = cx.tcx.hir_body(*body);
             let closure_expr = peel_blocks(body.value);
             match closure_expr.kind {
                 ExprKind::MethodCall(PathSegment { ident, .. }, receiver, ..) => {
@@ -404,7 +404,7 @@ fn is_find_or_filter<'a>(
     if is_trait_method(cx, map_recv, sym::Iterator)
         // filter(|x| ...is_some())...
         && let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind
-        && let filter_body = cx.tcx.hir().body(filter_body_id)
+        && let filter_body = cx.tcx.hir_body(filter_body_id)
         && let [filter_param] = filter_body.params
         // optional ref pattern: `filter(|&x| ..)`
         && let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
@@ -417,7 +417,7 @@ fn is_find_or_filter<'a>(
         && let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id)
 
         && let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind
-        && let map_body = cx.tcx.hir().body(map_body_id)
+        && let map_body = cx.tcx.hir_body(map_body_id)
         && let [map_param] = map_body.params
         && let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
index d550c145466..f7e116c5310 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
     if !expr.span.in_external_macro(cx.sess().source_map())
         && is_trait_method(cx, expr, sym::Iterator)
         && let ExprKind::Closure(closure) = arg.kind
-        && let body = cx.tcx.hir().body(closure.body)
+        && let body = cx.tcx.hir_body(closure.body)
         && let value = peel_blocks(body.value)
         // Indexing should be fine as `filter_map` always has 1 input, we unfortunately need both
         // `inputs` and `params` here as we need both the type and the span
@@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
         && is_copy(cx, param_ty)
         && let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind
         && let ExprKind::Closure(then_closure) = then_arg.kind
-        && let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value)
+        && let then_body = peel_blocks(cx.tcx.hir_body(then_closure.body).value)
         && let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id)
         && cx.tcx.is_diagnostic_item(sym::bool_then, def_id)
         && !is_from_proc_macro(cx, expr)
diff --git a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
index 3e5162ef458..1b28596d50d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
@@ -19,7 +19,7 @@ fn peel_non_expn_blocks<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) {
     if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String)
         && let ExprKind::Closure(closure) = map_arg.kind
-        && let body = cx.tcx.hir().body(closure.body)
+        && let body = cx.tcx.hir_body(closure.body)
         && let Some(value) = peel_non_expn_blocks(body.value)
         && let Some(mac) = root_macro_call_first_node(cx, value)
         && is_format_macro(cx, mac.def_id)
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
index 30387ba62a7..76a0c0061e5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
@@ -95,7 +95,7 @@ fn is_method(
             false
         },
         ExprKind::Closure(&hir::Closure { body, .. }) => {
-            let body = cx.tcx.hir().body(body);
+            let body = cx.tcx.hir_body(body);
             let closure_expr = peel_blocks(body.value);
             let params = body.params.iter().map(|param| param.pat).collect::<Vec<_>>();
             is_method(cx, closure_expr, type_symbol, method_name, params.as_slice())
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 299f6d10112..518041177e9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
         && let Body {
             params: [p],
             value: body_expr,
-        } = cx.tcx.hir().body(c.body)
+        } = cx.tcx.hir_body(c.body)
         && let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind
         && let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {
             (key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value),
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index 5ccb5243e90..a80977459f2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
             let ExprKind::Closure(closure) = expr.kind else {
                 return;
             };
-            let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else {
+            let body @ Body { params: [p], .. } = cx.tcx.hir_body(closure.body) else {
                 return;
             };
             let mut delegate = MoveDelegate {
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
index 20e4d233525..de37df2394d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
@@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
         && (is_diag_trait_item(cx, fn_id, sym::Iterator)
             || (msrv.meets(msrvs::OPTION_RESULT_INSPECT)
                 && (is_diag_item_method(cx, fn_id, sym::Option) || is_diag_item_method(cx, fn_id, sym::Result))))
-        && let body = cx.tcx.hir().body(c.body)
+        && let body = cx.tcx.hir_body(c.body)
         && let [param] = body.params
         && let PatKind::Binding(BindingMode(ByRef::No, Mutability::Not), arg_id, _, None) = param.pat.kind
         && let arg_ty = typeck.node_type(arg_id)
@@ -45,7 +45,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
         let can_lint = for_each_expr_without_closures(block.stmts, |e| {
             if let ExprKind::Closure(c) = e.kind {
                 // Nested closures don't need to treat returns specially.
-                let _: Option<!> = for_each_expr(cx, cx.tcx.hir().body(c.body).value, |e| {
+                let _: Option<!> = for_each_expr(cx, cx.tcx.hir_body(c.body).value, |e| {
                     if path_to_local_id(e, arg_id) {
                         let (kind, same_ctxt) = check_use(cx, e);
                         match (kind, same_ctxt && e.span.ctxt() == ctxt) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
index 4321dd6b0e0..8265c93bfe9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
@@ -44,7 +44,7 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
     match map_expr.kind {
         ExprKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, map_expr.hir_id), ResultOk) => true,
         ExprKind::Closure(closure) => {
-            let body = cx.tcx.hir().body(closure.body);
+            let body = cx.tcx.hir_body(closure.body);
             if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind
                 && let ExprKind::Call(callee, [ok_arg]) = body.value.kind
                 && is_res_lang_ctor(cx, path_res(cx, callee), ResultOk)
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index 1252f7ccd35..b2705e1ffc2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -47,7 +47,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
     {
         match arg.kind {
             hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
-                let closure_body = cx.tcx.hir().body(body);
+                let closure_body = cx.tcx.hir_body(body);
                 let closure_expr = peel_blocks(closure_body.value);
                 match closure_body.params[0].pat.kind {
                     hir::PatKind::Ref(inner, Mutability::Not) => {
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
index 162f0ac564d..5d0d4dae35f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
@@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) {
             fn_decl_span,
             ..
         }) = arg.kind
-        && let closure_body = cx.tcx.hir().body(body)
+        && let closure_body = cx.tcx.hir_body(body)
         && let [param] = closure_body.params
         && let PatKind::Wild = param.pat.kind
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs
index 78656ace831..35dd7c082c9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs
@@ -68,7 +68,7 @@ pub(super) fn check(
     let mut applicability = Applicability::MaybeIncorrect;
     if let Some(range) = higher::Range::hir(receiver)
         && let ExprKind::Closure(Closure { body, .. }) = arg.kind
-        && let body_hir = cx.tcx.hir().body(*body)
+        && let body_hir = cx.tcx.hir_body(*body)
         && let Body {
             params: [param],
             value: body_expr,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 0a8eafad0e8..ccc5cd4fa41 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -4716,7 +4716,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             if sig.decl.implicit_self.has_implicit_self()
                 && !(self.avoid_breaking_exported_api
                     && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id))
-                && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next()
+                && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir_body(id)).next()
                 && let Some(first_arg_ty) = first_arg_ty_opt
             {
                 wrong_self_convention::check(
@@ -4852,7 +4852,7 @@ impl Methods {
                         ),
                         Some(("chars", recv, _, _, _))
                             if let ExprKind::Closure(arg) = arg.kind
-                                && let body = cx.tcx.hir().body(arg.body)
+                                && let body = cx.tcx.hir_body(arg.body)
                                 && let [param] = body.params =>
                         {
                             string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
index 6993150fb57..743aacf0588 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
@@ -99,7 +99,7 @@ fn handle_expr(
 
 pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>, is_all: bool) {
     if let ExprKind::Closure(&Closure { body, .. }) = closure_arg.kind
-        && let body = cx.tcx.hir().body(body)
+        && let body = cx.tcx.hir_body(body)
         && let Some(first_param) = body.params.first()
         && let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind
         && method.ident.name.as_str() == "chars"
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 2780c3f8af5..45f79dd44f2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -456,8 +456,8 @@ impl<'tcx> Visitor<'tcx> for UsedCountVisitor<'_, 'tcx> {
         }
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
@@ -498,7 +498,7 @@ fn get_captured_ids(cx: &LateContext<'_>, ty: Ty<'_>) -> HirIdSet {
                 }
             },
             ty::Closure(def_id, _) => {
-                let closure_hir_node = cx.tcx.hir().get_if_local(*def_id).unwrap();
+                let closure_hir_node = cx.tcx.hir_get_if_local(*def_id).unwrap();
                 if let Node::Expr(closure_expr) = closure_hir_node {
                     can_move_expr_to_closure(cx, closure_expr)
                         .unwrap()
diff --git a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
index b71f79f8482..e0905374dda 100644
--- a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
@@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(
 
         let if_then = match then_method_name {
             "then" if let ExprKind::Closure(closure) = then_arg.kind => {
-                let body = cx.tcx.hir().body(closure.body);
+                let body = cx.tcx.hir_body(closure.body);
                 snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
             },
             "then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 8d97d1c72a6..469fcccbe4f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -54,7 +54,7 @@ pub(super) fn check(
                 })
         },
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
-            let closure_body = cx.tcx.hir().body(body);
+            let closure_body = cx.tcx.hir_body(body);
             let closure_expr = peel_blocks(closure_body.value);
 
             match &closure_expr.kind {
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
index 193deafccf6..1a273f77fb7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
@@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(
         let self_snippet = snippet(cx, recv.span, "..");
         if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind
             && let arg_snippet = snippet(cx, fn_decl_span, "..")
-            && let body = cx.tcx.hir().body(body)
+            && let body = cx.tcx.hir_body(body)
             && let Some((func, [arg_char])) = reduce_unit_expression(body.value)
             && let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id))
             && Some(id) == cx.tcx.lang_items().option_some_variant()
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index 7c4dc4ffb20..b1107d8cc72 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -58,8 +58,7 @@ pub(super) fn check<'tcx>(
                 unwrap_or_span: unwrap_arg.span,
             };
 
-            let map = cx.tcx.hir();
-            let body = map.body_owned_by(map.enclosing_body_owner(expr.hir_id));
+            let body = cx.tcx.hir_body_owned_by(cx.tcx.hir_enclosing_body_owner(expr.hir_id));
 
             // Visit the body, and return if we've found a reference
             if reference_visitor.visit_body(body).is_break() {
@@ -143,8 +142,8 @@ impl<'tcx> Visitor<'tcx> for UnwrapVisitor<'_, 'tcx> {
         walk_path(self, path);
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
@@ -174,7 +173,7 @@ impl<'tcx> Visitor<'tcx> for ReferenceVisitor<'_, 'tcx> {
         rustc_hir::intravisit::walk_expr(self, expr)
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 6b39b753885..f5f404070ca 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -253,7 +253,7 @@ pub(super) fn check<'tcx>(
 
 fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
     if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
-        let body = cx.tcx.hir().body(body);
+        let body = cx.tcx.hir_body(body);
 
         if body.params.is_empty()
             && let hir::Expr { kind, .. } = &body.value
diff --git a/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs
index 3b0dc506305..af619c9e3bb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
         // We check that it is mapped as `Some`.
         && is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome)
         && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = def_arg.kind
-        && let body = cx.tcx.hir().body(body)
+        && let body = cx.tcx.hir_body(body)
         // And finally we check that we return a `None` in the "else case".
         && is_res_lang_ctor(cx, path_res(cx, peel_blocks(body.value)), OptionNone)
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
index 7b1199ad1e2..68ffa81a278 100644
--- a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
@@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
     };
 
     let closure_arg = fn_decl.inputs[0];
-    let closure_expr = peel_blocks(cx.tcx.hir().body(body).value);
+    let closure_expr = peel_blocks(cx.tcx.hir_body(body).value);
 
     let mut applicability = Applicability::MachineApplicable;
     let arg_snip = snippet_with_applicability(cx, closure_arg.span, "_", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index 4ab165a5528..97c8ce2bcdd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(
             let mut applicability = Applicability::MachineApplicable;
             let any_search_snippet = if search_method == "find"
                 && let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind
-                && let closure_body = cx.tcx.hir().body(body)
+                && let closure_body = cx.tcx.hir_body(body)
                 && let Some(closure_arg) = closure_body.params.first()
             {
                 if let PatKind::Ref(..) = closure_arg.pat.kind {
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
index ed49233acb7..1bd48525f12 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
@@ -10,7 +10,7 @@ use super::SUSPICIOUS_MAP;
 pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
     if is_trait_method(cx, count_recv, sym::Iterator)
         && let hir::ExprKind::Closure(closure) = expr_or_init(cx, map_arg).kind
-        && let closure_body = cx.tcx.hir().body(closure.body)
+        && let closure_body = cx.tcx.hir_body(closure.body)
         && !cx.typeck_results().expr_ty(closure_body.value).is_unit()
     {
         if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index 5b9e9e70e47..ca42a9ac04e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -20,7 +20,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
     }
 
     if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
-        let body = cx.tcx.hir().body(body);
+        let body = cx.tcx.hir_body(body);
         let arg_id = body.params[0].pat.hir_id;
         let mutates_arg = mutated_variables(body.value, cx).is_none_or(|used_mutably| used_mutably.contains(&arg_id));
         let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, body.value);
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index e7adf3b43ba..8e3cc9abe83 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -62,7 +62,7 @@ fn check_fold_with_op(
 ) {
     if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind
         // Extract the body of the closure passed to fold
-        && let closure_body = cx.tcx.hir().body(body)
+        && let closure_body = cx.tcx.hir_body(body)
         && let closure_expr = peel_blocks(closure_body.value)
 
         // Check if the closure body is of the form `acc <op> some_expr(x)`
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 7af550fa7c6..9f4080100da 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(
 
     if is_option || is_result || is_bool {
         if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind {
-            let body = cx.tcx.hir().body(body);
+            let body = cx.tcx.hir_body(body);
             let body_expr = &body.value;
 
             if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index 10112b62878..00690aca6d1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -99,7 +99,7 @@ pub(super) fn check(
             ("None", "unwrap_or_else", _) => match args[0].kind {
                 hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![
                     (
-                        expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()),
+                        expr.span.with_hi(cx.tcx.hir_body(*body).value.span.lo()),
                         String::new(),
                     ),
                     (expr.span.with_lo(args[0].span.hi()), String::new()),
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
index 6dea1506d0e..5f88a7fd31f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
@@ -63,7 +63,7 @@ pub(super) fn check<'a>(
     let ext_def_span = def.span.until(map.span);
 
     let (sugg, method, applicability) = if let ExprKind::Closure(map_closure) = map.kind
-            && let closure_body = cx.tcx.hir().body(map_closure.body)
+            && let closure_body = cx.tcx.hir_body(map_closure.body)
             && let closure_body_value = closure_body.value.peel_blocks()
             && let ExprKind::Binary(op, l, r) = closure_body_value.kind
             && let Some(param) = closure_body.params.first()
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
index dc50717112d..f84d0d6dff0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
@@ -53,7 +53,7 @@ pub(super) fn check<'tcx>(
     // lint if the caller of `map_or_else()` is a `Result`
     if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
         && let ExprKind::Closure(&Closure { body, .. }) = map_arg.kind
-        && let body = cx.tcx.hir().body(body)
+        && let body = cx.tcx.hir_body(body)
         && let Some(first_param) = body.params.first()
     {
         let body_expr = peel_blocks(body.value);
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
index f0b29213e1e..fb4984914eb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -117,7 +117,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
         && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
         && cx.tcx.type_of(impl_id).instantiate_identity().is_slice()
         && let ExprKind::Closure(&Closure { body, .. }) = arg.kind
-        && let closure_body = cx.tcx.hir().body(body)
+        && let closure_body = cx.tcx.hir_body(body)
         && let &[
             Param {
                 pat:
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 7d72310c1c4..e80d99dca56 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
@@ -506,7 +506,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                     if has_lifetime(output_ty) && has_lifetime(ty) {
                         return false;
                     }
-                    let body = cx.tcx.hir().body(*body_id);
+                    let body = cx.tcx.hir_body(*body_id);
                     let body_expr = &body.value;
                     let mut count = 0;
                     return find_all_ret_expressions(cx, body_expr, |_| {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
index 0aec26f1011..af466fe091c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
@@ -46,7 +46,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
         && is_trait_method(cx, call_expr, sym::Iterator)
         // And the map argument is a closure
         && let ExprKind::Closure(closure) = closure_arg.kind
-        && let closure_body = cx.tcx.hir().body(closure.body)
+        && let closure_body = cx.tcx.hir_body(closure.body)
         // And that closure has one argument ...
         && let [closure_param] = closure_body.params
         // .. which is a tuple of 2 elements
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index 82313257e5c..19152362fb5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -113,7 +113,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
     match arg.kind {
         hir::ExprKind::Closure(&hir::Closure { body, .. })
             // If it's a closure, we need to check what is called.
-            if let closure_body = cx.tcx.hir().body(body)
+            if let closure_body = cx.tcx.hir_body(body)
                 && let [param] = closure_body.params
                 && let hir::PatKind::Binding(_, local_id, ..) = strip_pat_refs(param.pat).kind =>
         {
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index 6e39e7be2c4..3611b341897 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -89,8 +89,8 @@ struct CloneOrCopyVisitor<'cx, 'tcx> {
 impl<'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index e9ec23b1efa..675989156ca 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -213,8 +213,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
             && !item.span.from_expansion()
             // find `Debug::fmt` function
             && let Some(fmt_item) = items.iter().find(|i| i.ident.name == sym::fmt)
-            && let ImplItem { kind: ImplItemKind::Fn(_, body_id), .. } = cx.tcx.hir().impl_item(fmt_item.id)
-            && let body = cx.tcx.hir().body(*body_id)
+            && let ImplItem { kind: ImplItemKind::Fn(_, body_id), .. } = cx.tcx.hir_impl_item(fmt_item.id)
+            && let body = cx.tcx.hir_body(*body_id)
             && let ExprKind::Block(block, _) = body.value.kind
             // inspect `self`
             && let self_ty = cx.tcx.type_of(self_path_did).skip_binder().peel_refs()
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 18385ac9269..fdc0930e957 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
                 // note: we need to check if the trait is exported so we can't use
                 // `LateLintPass::check_trait_item` here.
                 for tit in trait_items {
-                    let tit_ = cx.tcx.hir().trait_item(tit.id);
+                    let tit_ = cx.tcx.hir_trait_item(tit.id);
                     match tit_.kind {
                         hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
                         hir::TraitItemKind::Fn(..) => {
@@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
                                 // trait method with default body needs inline in case
                                 // an impl is not provided
                                 let desc = "a default trait method";
-                                let item = cx.tcx.hir().trait_item(tit.id);
+                                let item = cx.tcx.hir_trait_item(tit.id);
                                 let attrs = cx.tcx.hir().attrs(item.hir_id());
                                 check_missing_inline_attrs(cx, attrs, item.span, desc);
                             }
diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
index 152635a5c35..13a23a13b9c 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -119,7 +119,7 @@ impl<'tcx> Visitor<'tcx> for MutArgVisitor<'_, 'tcx> {
         walk_expr(self, expr);
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
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 7f91e555054..ea1d7e5d438 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
@@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> {
         if self
             .possible_borrowers
             .last()
-            .is_some_and(|&(local_def_id, _)| local_def_id == cx.tcx.hir().body_owner_def_id(body.id()))
+            .is_some_and(|&(local_def_id, _)| local_def_id == cx.tcx.hir_body_owner_def_id(body.id()))
         {
             self.possible_borrowers.pop();
         }
@@ -359,7 +359,7 @@ fn referent_used_exactly_once<'tcx>(
         && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
         && !place.is_indirect_first_projection()
     {
-        let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
+        let body_owner_local_def_id = cx.tcx.hir_enclosing_body_owner(reference.hir_id);
         if possible_borrowers
             .last()
             .is_none_or(|&(local_def_id, _)| local_def_id != body_owner_local_def_id)
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 93e20f37ef8..90b27f5dbac 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
             // Skip the lint if the body is not block because this is simpler than `for` loop.
             // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop.
             && let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind
-            && let body = cx.tcx.hir().body(body)
+            && let body = cx.tcx.hir_body(body)
             // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}`
             // and suggesting `for … in … { unsafe { } }` is a little ugly.
             && let ExprKind::Block(Block { rules: BlockCheckMode::DefaultBlock, .. }, ..) = body.value.kind
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index 996251fdf16..5e85d23718a 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -103,7 +103,6 @@ fn check_closures<'tcx>(
     checked_closures: &mut FxHashSet<LocalDefId>,
     closures: FxIndexSet<LocalDefId>,
 ) {
-    let hir = cx.tcx.hir();
     for closure in closures {
         if !checked_closures.insert(closure) {
             continue;
@@ -114,7 +113,7 @@ fn check_closures<'tcx>(
             .tcx
             .hir_node_by_def_id(closure)
             .associated_body()
-            .map(|(_, body_id)| hir.body(body_id))
+            .map(|(_, body_id)| cx.tcx.hir_body(body_id))
         {
             euv::ExprUseVisitor::for_clippy(cx, closure, &mut *ctx)
                 .consume_body(body)
@@ -353,7 +352,7 @@ impl MutablyUsedVariablesCtxt<'_> {
     fn is_in_unsafe_block(&self, item: HirId) -> bool {
         let hir = self.tcx.hir();
         for (parent, node) in hir.parent_iter(item) {
-            if let Some(fn_sig) = hir.fn_sig_by_hir_id(parent) {
+            if let Some(fn_sig) = self.tcx.hir_fn_sig_by_hir_id(parent) {
                 return fn_sig.header.is_unsafe();
             } else if let Node::Block(block) = node {
                 if matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) {
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index cc56df3a23d..cf407e51f7a 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
         {
             for assoc_item in *items {
                 if assoc_item.kind == (hir::AssocItemKind::Fn { has_self: false }) {
-                    let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
+                    let impl_item = cx.tcx.hir_impl_item(assoc_item.id);
                     if impl_item.span.in_external_macro(cx.sess().source_map()) {
                         return;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
index dad1e8a3d6a..448bb603cf2 100644
--- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
@@ -121,10 +121,10 @@ impl LateLintPass<'_> for NonCanonicalImpls {
         if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) {
             return;
         }
-        let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else {
+        let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir_impl_item(impl_item.impl_item_id()).kind else {
             return;
         };
-        let body = cx.tcx.hir().body(impl_item_id);
+        let body = cx.tcx.hir_body(impl_item_id);
         let ExprKind::Block(block, ..) = body.value.kind else {
             return;
         };
diff --git a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
index 22116505a1c..774a182d089 100644
--- a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
+++ b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
@@ -214,7 +214,7 @@ impl LazyInfo {
             && state.once_cell_sync_lazy.contains(&path_def_id)
         {
             let ty_span_no_args = path_span_without_args(path);
-            let body = cx.tcx.hir().body(body_id);
+            let body = cx.tcx.hir_body(body_id);
 
             // visit body to collect `Lazy::new` calls
             let mut new_fn_calls = FxIndexMap::default();
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 9d07a14718d..594101427f5 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -349,10 +349,10 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
     }
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
-        let body_owner = cx.tcx.hir().body_owner(body.id());
-        let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
+        let body_owner = cx.tcx.hir_body_owner(body.id());
+        let body_owner_def_id = cx.tcx.hir_body_owner_def_id(body.id());
 
-        let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
+        let body_owner_kind = cx.tcx.hir_body_owner_kind(body_owner_def_id);
         if let hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) = body_owner_kind {
             let body_span = cx.tcx.hir().span_with_body(body_owner);
             if let Some(span) = self.const_span
@@ -365,7 +365,7 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
     }
 
     fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
-        let body_owner = cx.tcx.hir().body_owner(body.id());
+        let body_owner = cx.tcx.hir_body_owner(body.id());
         let body_span = cx.tcx.hir().span(body_owner);
         if let Some(span) = self.const_span
             && span.contains(body_span)
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index 2083f2bf628..cda99a362dc 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -68,10 +68,10 @@ impl Context {
     }
 
     pub fn enter_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
-        let body_owner = cx.tcx.hir().body_owner(body.id());
-        let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
+        let body_owner = cx.tcx.hir_body_owner(body.id());
+        let body_owner_def_id = cx.tcx.hir_body_owner_def_id(body.id());
 
-        match cx.tcx.hir().body_owner_kind(body_owner_def_id) {
+        match cx.tcx.hir_body_owner_kind(body_owner_def_id) {
             hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const { .. } => {
                 let body_span = cx.tcx.hir().span_with_body(body_owner);
 
@@ -87,7 +87,7 @@ impl Context {
     }
 
     pub fn body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
-        let body_owner = cx.tcx.hir().body_owner(body.id());
+        let body_owner = cx.tcx.hir_body_owner(body.id());
         let body_span = cx.tcx.hir().span_with_body(body_owner);
 
         if let Some(span) = self.const_span {
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 95403403217..73c31b83b51 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
@@ -136,7 +136,7 @@ impl PassByRefOrValue {
         }
 
         let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
-        let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));
+        let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir_body(id));
 
         // Gather all the lifetimes found in the output type which may affect whether
         // `TRIVIALLY_COPY_PASS_BY_REF` should be linted.
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 7fba4b6a6c8..9b241edf4cc 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -583,8 +583,8 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[
     }
     impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
         type NestedFilter = nested_filter::OnlyBodies;
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.cx.tcx.hir()
+        fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+            self.cx.tcx
         }
 
         fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index 65fd312b3a0..bc5e8fd2c25 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
 /// any variable by ref.
 fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if let ExprKind::Closure(Closure { body, def_id, kind, .. }) = expr.kind
-        && let body = cx.tcx.hir().body(*body)
+        && let body = cx.tcx.hir_body(*body)
         && matches!(
             kind,
             ClosureKind::Coroutine(CoroutineKind::Desugared(
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 91d023500ca..1498a49a7a4 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -90,7 +90,7 @@ fn find_innermost_closure<'tcx>(
     let mut data = None;
 
     while let ExprKind::Closure(closure) = expr.kind
-        && let body = cx.tcx.hir().body(closure.body)
+        && let body = cx.tcx.hir_body(closure.body)
         && {
             let mut visitor = ReturnVisitor;
             !visitor.visit_expr(body.value).is_break()
@@ -179,7 +179,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
                             // Like `async fn`, async closures are wrapped in an additional block
                             // to move all of the closure's arguments into the future.
 
-                            let async_closure_body = cx.tcx.hir().body(closure.body).value;
+                            let async_closure_body = cx.tcx.hir_body(closure.body).value;
                             let ExprKind::Block(block, _) = async_closure_body.kind else {
                                 return;
                             };
@@ -241,8 +241,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
                     hir_visit::walk_expr(self, expr);
                 }
 
-                fn nested_visit_map(&mut self) -> Self::Map {
-                    self.cx.tcx.hir()
+                fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+                    self.cx.tcx
                 }
             }
             let mut closure_usage_count = ClosureUsageCount { cx, path, count: 0 };
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index ebe3e7c2019..e15e1262920 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
 /// assert_static(closure);
 /// ```
 fn is_by_value_closure_capture(cx: &LateContext<'_>, redefinition: HirId, root_variable: HirId) -> bool {
-    let closure_def_id = cx.tcx.hir().enclosing_body_owner(redefinition);
+    let closure_def_id = cx.tcx.hir_enclosing_body_owner(redefinition);
 
     cx.tcx.is_closure_like(closure_def_id.to_def_id())
         && cx.tcx.closure_captures(closure_def_id).iter().any(|c| {
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index a1cf16e6ce9..9f0ea84246d 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -205,7 +205,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
             // Ensure this is not the final stmt, otherwise removing it would cause a compile error
             && let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir().get_parent_item(expr.hir_id))
             && let ItemKind::Fn { body, .. } = item.kind
-            && let block = cx.tcx.hir().body(body).value
+            && let block = cx.tcx.hir_body(body).value
             && let ExprKind::Block(block, _) = block.kind
             && !is_inside_let_else(cx.tcx, expr)
             && let [.., final_stmt] = block.stmts
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 29914d4379f..552135b15fd 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -50,9 +50,9 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
     fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
         let mut map = FxHashMap::<Res, ExistingName>::default();
 
-        for id in cx.tcx.hir().items() {
+        for id in cx.tcx.hir_free_items() {
             if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. })
-                && let item = cx.tcx.hir().item(id)
+                && let item = cx.tcx.hir_item(id)
                 && let ItemKind::Impl(Impl {
                     items,
                     of_trait,
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 83199ba0f70..a931e39bac9 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -149,17 +149,15 @@ impl<'tcx> LateLintPass<'tcx> for Shadow {
     }
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
-        let hir = cx.tcx.hir();
-        let owner_id = hir.body_owner_def_id(body.id());
-        if !matches!(hir.body_owner_kind(owner_id), BodyOwnerKind::Closure) {
+        let owner_id = cx.tcx.hir_body_owner_def_id(body.id());
+        if !matches!(cx.tcx.hir_body_owner_kind(owner_id), BodyOwnerKind::Closure) {
             self.bindings.push((FxHashMap::default(), owner_id));
         }
     }
 
     fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
-        let hir = cx.tcx.hir();
         if !matches!(
-            hir.body_owner_kind(hir.body_owner_def_id(body.id())),
+            cx.tcx.hir_body_owner_kind(cx.tcx.hir_body_owner_def_id(body.id())),
             BodyOwnerKind::Closure
         ) {
             self.bindings.pop();
diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs
index fdbccbaa8a5..1a2fb77acc1 100644
--- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs
@@ -90,8 +90,7 @@ impl SingleCallFn {
             || fn_span.in_external_macro(cx.sess().source_map())
             || cx
                 .tcx
-                .hir()
-                .maybe_body_owned_by(fn_def_id)
+                .hir_maybe_body_owned_by(fn_def_id)
                 .is_none_or(|body| is_in_test_function(cx.tcx, body.value.hir_id))
             || match cx.tcx.hir_node(fn_hir_id) {
                 Node::Item(item) => is_from_proc_macro(cx, item),
diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs
index 3834087f797..694ad4f6347 100644
--- a/src/tools/clippy/clippy_lints/src/string_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs
@@ -138,7 +138,7 @@ fn get_char_span<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Optio
 
 fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>, msrv: &Msrv) {
     if let ExprKind::Closure(closure) = method_arg.kind
-        && let body = cx.tcx.hir().body(closure.body)
+        && let body = cx.tcx.hir_body(closure.body)
         && let Some(PatKind::Binding(_, binding, ..)) = body.params.first().map(|p| p.pat.kind)
     {
         let mut set_char_spans: Vec<Span> = Vec::new();
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 6164a6191db..4a5f143a2d3 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{
-    SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, is_path_diagnostic_item,
-    method_calls, peel_blocks,
+    SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, path_def_id,
+    peel_blocks,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
@@ -253,8 +253,9 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         use rustc_ast::LitKind;
 
         if let ExprKind::Call(fun, [bytes_arg]) = e.kind
-            // Find std::str::converts::from_utf8
-            && is_path_diagnostic_item(cx, fun, sym::str_from_utf8)
+            // Find `std::str::converts::from_utf8` or `std::primitive::str::from_utf8`
+            && let Some(sym::str_from_utf8 | sym::str_inherent_from_utf8) =
+                path_def_id(cx, fun).and_then(|id| cx.tcx.get_diagnostic_name(id))
 
             // Find string::as_bytes
             && let ExprKind::AddrOf(BorrowKind::Ref, _, args) = bytes_arg.kind
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index e9779d437d4..9326b2adaff 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
             && let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id
             && let hir::Node::ImplItem(impl_item) = cx.tcx.hir_node_by_def_id(parent_fn)
             && let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind
-            && let body = cx.tcx.hir().body(body_id)
+            && let body = cx.tcx.hir_body(body_id)
             && let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id
             && let Some(trait_ref) = trait_ref_of_method(cx, parent_fn)
             && let trait_id = trait_ref.path.res.def_id()
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 790e0965198..cbf7b126632 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                 && let Some(Node::Item(Item {
                     kind: ItemKind::Trait(_, _, _, self_bounds, _),
                     ..
-                })) = cx.tcx.hir().get_if_local(*def_id)
+                })) = cx.tcx.hir_get_if_local(*def_id)
             {
                 if self_bounds_map.is_empty() {
                     for bound in *self_bounds {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
index 4961dd6b280..0b5d83ef58c 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
@@ -28,8 +28,8 @@ fn get_parent_local_binding_ty<'tcx>(cx: &LateContext<'tcx>, expr_hir_id: HirId)
 }
 
 fn is_function_block(cx: &LateContext<'_>, expr_hir_id: HirId) -> bool {
-    let def_id = cx.tcx.hir().enclosing_body_owner(expr_hir_id);
-    if let Some(body) = cx.tcx.hir().maybe_body_owned_by(def_id) {
+    let def_id = cx.tcx.hir_enclosing_body_owner(expr_hir_id);
+    if let Some(body) = cx.tcx.hir_maybe_body_owned_by(def_id) {
         return body.value.peel_blocks().hir_id == expr_hir_id;
     }
     false
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index 2e97772407f..004ad03e708 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -96,10 +96,10 @@ fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool {
 
 fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option<GenericBounds<'tcx>> {
     if let Some(did) = cx.qpath_res(qpath, id).opt_def_id()
-        && let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did)
+        && let Some(Node::GenericParam(generic_param)) = cx.tcx.hir_get_if_local(did)
         && let GenericParamKind::Type { synthetic, .. } = generic_param.kind
         && synthetic
-        && let Some(generics) = cx.tcx.hir().get_generics(id.owner.def_id)
+        && let Some(generics) = cx.tcx.hir_get_generics(id.owner.def_id)
         && let Some(pred) = generics.bounds_for_param(did.expect_local()).next()
     {
         Some(pred.bounds)
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index 207f2ef4563..76a0b927df4 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -9,7 +9,6 @@ use rustc_hir::intravisit::{FnKind, Visitor, walk_body, walk_expr};
 use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath, TyKind};
 use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt};
 use rustc_session::impl_lint_pass;
@@ -275,7 +274,6 @@ fn is_default_method_on_current_ty<'tcx>(tcx: TyCtxt<'tcx>, qpath: QPath<'tcx>,
 
 struct CheckCalls<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    map: Map<'tcx>,
     implemented_ty_id: DefId,
     method_span: Span,
 }
@@ -287,8 +285,8 @@ where
     type NestedFilter = nested_filter::OnlyBodies;
     type Result = ControlFlow<()>;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.map
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow<()> {
@@ -326,15 +324,15 @@ impl UnconditionalRecursion {
                             .find(|item| {
                                 item.kind == AssocKind::Fn && item.def_id.is_local() && item.name == kw::Default
                             })
-                        && let Some(body_node) = cx.tcx.hir().get_if_local(assoc_item.def_id)
+                        && let Some(body_node) = cx.tcx.hir_get_if_local(assoc_item.def_id)
                         && let Some(body_id) = body_node.body_id()
-                        && let body = cx.tcx.hir().body(body_id)
+                        && let body = cx.tcx.hir_body(body_id)
                         // We don't want to keep it if it has conditional return.
                         && let [return_expr] = get_return_calls_in_body(body).as_slice()
                         && let ExprKind::Call(call_expr, _) = return_expr.kind
                         // We need to use typeck here to infer the actual function being called.
-                        && let body_def_id = cx.tcx.hir().enclosing_body_owner(call_expr.hir_id)
-                        && let Some(body_owner) = cx.tcx.hir().maybe_body_owned_by(body_def_id)
+                        && let body_def_id = cx.tcx.hir_enclosing_body_owner(call_expr.hir_id)
+                        && let Some(body_owner) = cx.tcx.hir_maybe_body_owned_by(body_def_id)
                         && let typeck = cx.tcx.typeck_body(body_owner.id())
                         && let Some(call_def_id) = typeck.type_dependent_def_id(call_expr.hir_id)
                     {
@@ -380,7 +378,6 @@ impl UnconditionalRecursion {
         {
             let mut c = CheckCalls {
                 cx,
-                map: cx.tcx.hir(),
                 implemented_ty_id,
                 method_span,
             };
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index b3d26908093..c8e3c46f2f6 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -245,7 +245,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
             // const and static items only need a safety comment if their body is an unsafe block, lint otherwise
             (&ItemKind::Const(.., body) | &ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => {
                 if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) {
-                    let body = cx.tcx.hir().body(body);
+                    let body = cx.tcx.hir_body(body);
                     if !matches!(
                         body.value.kind, hir::ExprKind::Block(block, _)
                         if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
@@ -558,7 +558,7 @@ fn comment_start_before_item_in_mod(
                 // some_item /* comment */ unsafe impl T {}
                 // ^-------^ returns the end of this span
                 //         ^---------------^ finally checks comments in this range
-                let prev_item = cx.tcx.hir().item(parent_mod.item_ids[idx - 1]);
+                let prev_item = cx.tcx.hir_item(parent_mod.item_ids[idx - 1]);
                 if let Some(sp) = walk_span_to_context(prev_item.span, SyntaxContext::root()) {
                     return Some(sp.hi());
                 }
@@ -605,7 +605,7 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span
 fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
     let body = cx.enclosing_body?;
     let map = cx.tcx.hir();
-    let mut span = map.body(body).value.span;
+    let mut span = cx.tcx.hir_body(body).value.span;
     let mut maybe_global_var = false;
     for (_, node) in map.parent_iter(body.hir_id) {
         match node {
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index 87478a120dd..67ceac92dbc 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -123,7 +123,7 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
         && let ty = cx.tcx.instantiate_bound_regions_with_erased(ret_ty)
         && ty.is_unit()
     {
-        let body = cx.tcx.hir().body(body);
+        let body = cx.tcx.hir_body(body);
         if let ExprKind::Block(block, _) = body.value.kind
             && block.expr.is_none()
             && let Some(stmt) = block.stmts.last()
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index 00b80e827d8..87f184e13ce 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
                     if let PatKind::Binding(_, binding_hir_id, ..) = local.pat.kind
                         && let Some(body_id) = cx.enclosing_body.as_ref()
                     {
-                        let body = cx.tcx.hir().body(*body_id);
+                        let body = cx.tcx.hir_body(*body_id);
 
                         // Collect variable usages
                         let mut visitor = UnitVariableCollector::new(binding_hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index d00bd7f2b3d..1c1c841e964 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -101,8 +101,8 @@ impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> {
         }
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index 71aa57e0a14..0f9b05c84d4 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -112,8 +112,8 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
     type NestedFilter = OnlyBodies;
     type Result = ControlFlow<()>;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow<()> {
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index 781f51aa9b0..d8305a62829 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
             && assoc_item.fn_has_self_parameter
             && let ImplItemKind::Fn(.., body_id) = &impl_item.kind
             && (!cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api)
-            && let body = cx.tcx.hir().body(*body_id)
+            && let body = cx.tcx.hir_body(*body_id)
             && let [self_param, ..] = body.params
             && !is_local_used(cx, body, self_param.pat.hir_id)
             && !contains_todo(cx, body)
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 6a952c0d97a..76b9bbbd32f 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -374,8 +374,8 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
         }
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index 9b9a2ffbbc8..f870eb71e19 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
 
 fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) {
     if let ImplItemKind::Fn(_, body_id) = impl_item.kind {
-        let body = cx.tcx.hir().body(body_id);
+        let body = cx.tcx.hir_body(body_id);
         let typeck = cx.tcx.typeck(impl_item.owner_id.def_id);
         let mut result = Vec::new();
         let _: Option<!> = for_each_expr(cx, body.value, |e| {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 6bad78cf871..5fc166438e8 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -132,8 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
 }
 
 fn check_item(cx: &LateContext<'_>, hir_id: HirId) {
-    let hir = cx.tcx.hir();
-    if let Some(body) = hir.maybe_body_owned_by(hir_id.expect_owner().def_id) {
+    if let Some(body) = cx.tcx.hir_maybe_body_owned_by(hir_id.expect_owner().def_id) {
         check_node(cx, hir_id, |v| {
             v.expr(&v.bind("expr", body.value));
         });
@@ -637,9 +636,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     }
 
     fn body(&self, body_id: &Binding<hir::BodyId>) {
-        let expr = self.cx.tcx.hir().body(body_id.value).value;
+        let expr = self.cx.tcx.hir_body(body_id.value).value;
         bind!(self, expr);
-        chain!(self, "{expr} = &cx.tcx.hir().body({body_id}).value");
+        chain!(self, "{expr} = &cx.tcx.hir_body({body_id}).value");
         self.expr(expr);
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
index eaeb754a23f..2e6fb7c4ce4 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
@@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
         if let ExprKind::Call(func, [call_cx, call_lint, call_sp, call_msg, call_f]) = expr.kind
             && is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"])
             && let ExprKind::Closure(&Closure { body, .. }) = call_f.kind
-            && let body = cx.tcx.hir().body(body)
+            && let body = cx.tcx.hir_body(body)
             && let only_expr = peel_blocks_with_stmt(body.value)
             && let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind
             && let ExprKind::Path(..) = recv.kind
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index 08c178ed229..252ac5e6768 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -37,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
                 ty::TypingEnv::post_analysis(cx.tcx, item.owner_id),
                 cx.tcx.typeck(item.owner_id),
             )
-            .eval_simple(cx.tcx.hir().body(body_id).value)
+            .eval_simple(cx.tcx.hir_body(body_id).value)
             && let Some(path) = path
                 .iter()
                 .map(|x| {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
index dac1951489c..d6f10f1e4b8 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
             if is_lint_ref_type(cx, ty) {
                 check_invalid_clippy_version_attribute(cx, item);
 
-                let expr = &cx.tcx.hir().body(body_id).value;
+                let expr = &cx.tcx.hir_body(body_id).value;
                 let fields = if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind
                     && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind
                 {
@@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
                     output: &mut self.registered_lints,
                     cx,
                 };
-                let body = cx.tcx.hir().body_owned_by(
+                let body = cx.tcx.hir_body_owned_by(
                     impl_item_refs
                         .iter()
                         .find(|iiref| iiref.ident.as_str() == "lint_vec")
@@ -277,7 +277,7 @@ impl<'tcx> Visitor<'tcx> for LintCollector<'_, 'tcx> {
         }
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
         self.cx.tcx.hir()
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs
index 05f85650769..30fdf22fdbb 100644
--- a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs
@@ -47,7 +47,6 @@ declare_lint_pass!(ZeroRepeatSideEffects => [ZERO_REPEAT_SIDE_EFFECTS]);
 
 impl LateLintPass<'_> for ZeroRepeatSideEffects {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &rustc_hir::Expr<'_>) {
-        let hir_map = cx.tcx.hir();
         if let Some(args) = VecArgs::hir(cx, expr)
             && let VecArgs::Repeat(inner_expr, len) = args
             && let ExprKind::Lit(l) = len.kind
@@ -62,7 +61,7 @@ impl LateLintPass<'_> for ZeroRepeatSideEffects {
         // sessions).
         else if let ExprKind::Repeat(inner_expr, const_arg) = expr.kind
             && let ConstArgKind::Anon(anon_const) = const_arg.kind
-            && let length_expr = hir_map.body(anon_const.body).value
+            && let length_expr = cx.tcx.hir_body(anon_const.body).value
             && !length_expr.span.from_expansion()
             && let ExprKind::Lit(literal) = length_expr.kind
             && let LitKind::Int(Pu128(0), _) = literal.node
diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
index 4df34891a2b..9bd00b1e5c8 100644
--- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs
+++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
@@ -249,8 +249,8 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> {
         walk_expr(self, ex)
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 59aaaa3d9fb..4f48fb3b8a9 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -192,7 +192,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
             },
             ExprKind::Closure(&Closure { body, .. }) => (
                 Pat::Str(""),
-                expr_search_pat_inner(tcx, tcx.hir().body(body).value, outer_span).1,
+                expr_search_pat_inner(tcx, tcx.hir_body(body).value, outer_span).1,
             ),
             ExprKind::Block(
                 Block {
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index db82c458f70..4f707e34abf 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -455,7 +455,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                     Some(val)
                 }
             },
-            PatExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(*body).value),
+            PatExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir_body(*body).value),
             PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id),
         }
     }
@@ -483,7 +483,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
     /// Simple constant folding: Insert an expression, get a constant or none.
     fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
         match e.kind {
-            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
+            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir_body(body).value),
             ExprKind::DropTemps(e) => self.expr(e),
             ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id),
             ExprKind::Block(block, _) => self.block(block),
@@ -550,7 +550,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
     /// leaves the local crate.
     pub fn eval_is_empty(&self, e: &Expr<'_>) -> Option<bool> {
         match e.kind {
-            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.eval_is_empty(self.tcx.hir().body(body).value),
+            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.eval_is_empty(self.tcx.hir_body(body).value),
             ExprKind::DropTemps(e) => self.eval_is_empty(e),
             ExprKind::Path(ref qpath) => {
                 if !self
@@ -645,7 +645,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
             Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
                 // Check if this constant is based on `cfg!(..)`,
                 // which is NOT constant for our purposes.
-                if let Some(node) = self.tcx.hir().get_if_local(def_id)
+                if let Some(node) = self.tcx.hir_get_if_local(def_id)
                     && let Node::Item(Item {
                         kind: ItemKind::Const(.., body_id),
                         ..
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 4bbf28115a6..9ee30094d60 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -273,8 +273,8 @@ impl HirEqInterExpr<'_, '_, '_> {
             self.inner.cx.tcx.typeck_body(right),
         ));
         let res = self.eq_expr(
-            self.inner.cx.tcx.hir().body(left).value,
-            self.inner.cx.tcx.hir().body(right).value,
+            self.inner.cx.tcx.hir_body(left).value,
+            self.inner.cx.tcx.hir_body(right).value,
         );
         self.inner.maybe_typeck_results = old_maybe_typeck_results;
         res
@@ -906,7 +906,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             }) => {
                 std::mem::discriminant(&capture_clause).hash(&mut self.s);
                 // closures inherit TypeckResults
-                self.hash_expr(self.cx.tcx.hir().body(body).value);
+                self.hash_expr(self.cx.tcx.hir_body(body).value);
             },
             ExprKind::ConstBlock(ref l_id) => {
                 self.hash_body(l_id.body);
@@ -1316,7 +1316,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
     pub fn hash_body(&mut self, body_id: BodyId) {
         // swap out TypeckResults when hashing a body
         let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id));
-        self.hash_expr(self.cx.tcx.hir().body(body_id).value);
+        self.hash_expr(self.cx.tcx.hir_body(body_id).value);
         self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 79cc5066580..15e395731ad 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -237,8 +237,7 @@ pub fn is_in_const_context(cx: &LateContext<'_>) -> bool {
     debug_assert!(cx.enclosing_body.is_some(), "`LateContext` has no enclosing body");
     cx.enclosing_body.is_some_and(|id| {
         cx.tcx
-            .hir()
-            .body_const_context(cx.tcx.hir().body_owner_def_id(id))
+            .hir_body_const_context(cx.tcx.hir_body_owner_def_id(id))
             .is_some()
     })
 }
@@ -251,8 +250,7 @@ pub fn is_in_const_context(cx: &LateContext<'_>) -> bool {
 ///  * associated constants
 pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
     use ConstContext::{Const, ConstFn, Static};
-    let hir = tcx.hir();
-    let Some(ctx) = hir.body_const_context(hir.enclosing_body_owner(hir_id)) else {
+    let Some(ctx) = tcx.hir_body_const_context(tcx.hir_enclosing_body_owner(hir_id)) else {
         return false;
     };
     match ctx {
@@ -652,8 +650,6 @@ fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol)
 }
 
 fn local_item_children_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, name: Symbol) -> Vec<Res> {
-    let hir = tcx.hir();
-
     let root_mod;
     let item_kind = match tcx.hir_node_by_def_id(local_id) {
         Node::Crate(r#mod) => {
@@ -677,7 +673,7 @@ fn local_item_children_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, name: Symb
         ItemKind::Mod(r#mod) => r#mod
             .item_ids
             .iter()
-            .filter_map(|&item_id| res(hir.item(item_id).ident, item_id.owner_id))
+            .filter_map(|&item_id| res(tcx.hir_item(item_id).ident, item_id.owner_id))
             .collect(),
         ItemKind::Impl(r#impl) => r#impl
             .items
@@ -944,7 +940,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
         ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
         ExprKind::Repeat(x, len) => {
             if let ConstArgKind::Anon(anon_const) = len.kind
-                && let ExprKind::Lit(const_lit) = cx.tcx.hir().body(anon_const.body).value.kind
+                && let ExprKind::Lit(const_lit) = cx.tcx.hir_body(anon_const.body).value.kind
                 && let LitKind::Int(v, _) = const_lit.node
                 && v <= 32
                 && is_default_equivalent(cx, x)
@@ -974,7 +970,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
             ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
             ExprKind::Repeat(_, len) => {
                 if let ConstArgKind::Anon(anon_const) = len.kind
-                    && let ExprKind::Lit(const_lit) = cx.tcx.hir().body(anon_const.body).value.kind
+                    && let ExprKind::Lit(const_lit) = cx.tcx.hir_body(anon_const.body).value.kind
                     && let LitKind::Int(v, _) = const_lit.node
                 {
                     return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
@@ -1372,8 +1368,8 @@ impl<'tcx> Visitor<'tcx> for ContainsName<'_, 'tcx> {
         }
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
@@ -1424,7 +1420,7 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio
         | Node::ImplItem(&ImplItem {
             kind: ImplItemKind::Fn(_, eid),
             ..
-        }) => match cx.tcx.hir().body(eid).value.kind {
+        }) => match cx.tcx.hir_body(eid).value.kind {
             ExprKind::Block(block, _) => Some(block),
             _ => None,
         },
@@ -1650,7 +1646,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
     if is_integer_literal(e, value) {
         return true;
     }
-    let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id);
+    let enclosing_body = cx.tcx.hir_enclosing_body_owner(e.hir_id);
     if let Some(Constant::Int(v)) =
         ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), cx.tcx.typeck(enclosing_body)).eval(e)
     {
@@ -2067,7 +2063,7 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t
                 ..
             },
             _,
-        ) = tcx.hir().body(body).value.kind
+        ) = tcx.hir_body(body).value.kind
         {
             return Some(expr);
         }
@@ -2175,7 +2171,7 @@ pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>)
         ExprKind::Closure(&Closure { body, fn_decl, .. })
             if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(()))) =>
         {
-            is_body_identity_function(cx, cx.tcx.hir().body(body))
+            is_body_identity_function(cx, cx.tcx.hir_body(body))
         },
         ExprKind::Path(QPath::Resolved(_, path))
             if path.segments.iter().all(|seg| seg.infer_args)
@@ -2197,7 +2193,7 @@ pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>)
 /// errors.
 pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match expr.kind {
-        ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)),
+        ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir_body(body)),
         _ => path_def_id(cx, expr).is_some_and(|id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)),
     }
 }
@@ -2552,9 +2548,9 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym
         Entry::Occupied(entry) => f(entry.get()),
         Entry::Vacant(entry) => {
             let mut names = Vec::new();
-            for id in tcx.hir().module_items(module) {
+            for id in tcx.hir_module_free_items(module) {
                 if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
-                    && let item = tcx.hir().item(id)
+                    && let item = tcx.hir_item(id)
                     && let ItemKind::Const(ty, _generics, _body) = item.kind
                 {
                     if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
@@ -2764,7 +2760,7 @@ impl<'tcx> ExprUseCtxt<'tcx> {
 
             Node::Expr(use_expr) => match use_expr.kind {
                 ExprKind::Ret(_) => ExprUseNode::Return(OwnerId {
-                    def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
+                    def_id: cx.tcx.hir_body_owner_def_id(cx.enclosing_body.unwrap()),
                 }),
 
                 ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
@@ -2932,7 +2928,7 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprU
         #[allow(unreachable_patterns)]
         Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow<!>"),
         None => ExprUseCtxt {
-            node: Node::Crate(cx.tcx.hir().root_module()),
+            node: Node::Crate(cx.tcx.hir_root_module()),
             child_id: HirId::INVALID,
             adjustments: &[],
             is_ty_unified: true,
diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs
index 85250f81dc4..637c0bafd96 100644
--- a/src/tools/clippy/clippy_utils/src/mir/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs
@@ -136,8 +136,8 @@ pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option<bool> {
 /// Returns the `mir::Body` containing the node associated with `hir_id`.
 #[allow(clippy::module_name_repetitions)]
 pub fn enclosing_mir(tcx: TyCtxt<'_>, hir_id: HirId) -> Option<&Body<'_>> {
-    let body_owner_local_def_id = tcx.hir().enclosing_body_owner(hir_id);
-    if tcx.hir().body_owner_kind(body_owner_local_def_id).is_fn_or_closure() {
+    let body_owner_local_def_id = tcx.hir_enclosing_body_owner(hir_id);
+    if tcx.hir_body_owner_kind(body_owner_local_def_id).is_fn_or_closure() {
         Some(tcx.optimized_mir(body_owner_local_def_id.to_def_id()))
     } else {
         None
diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs
index 273c1b0defa..360c6251a57 100644
--- a/src/tools/clippy/clippy_utils/src/ptr.rs
+++ b/src/tools/clippy/clippy_utils/src/ptr.rs
@@ -13,7 +13,7 @@ pub fn get_spans(
     idx: usize,
     replacements: &[(&'static str, &'static str)],
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
-    if let Some(body) = opt_body_id.map(|id| cx.tcx.hir().body(id)) {
+    if let Some(body) = opt_body_id.map(|id| cx.tcx.hir_body(id)) {
         if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind {
             extract_clone_suggestions(cx, binding_id, replacements, body)
         } else {
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 088abd7c479..d5e0e2e3436 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -809,7 +809,7 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti
         fn_decl, def_id, body, ..
     }) = closure.kind
     {
-        let closure_body = cx.tcx.hir().body(body);
+        let closure_body = cx.tcx.hir_body(body);
         // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
         // a type annotation is present if param `kind` is different from `TyKind::Infer`
         let closure_arg_is_type_annotated_double_ref = if let TyKind::Ref(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index a5374f6904e..8eef6a7f57e 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -267,7 +267,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
     // through calling `body_owner_kind`, which would panic if the callee
     // does not have a body.
     if let Some(callee_id) = callee_id {
-        let _ = tcx.hir().body_owner_kind(callee_id);
+        let _ = tcx.hir_body_owner_kind(callee_id);
     }
 
     let ty = tcx.erase_regions(ty);
@@ -705,7 +705,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
         ty::Closure(id, subs) => {
             let decl = id
                 .as_local()
-                .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.local_def_id_to_hir_id(id)));
+                .and_then(|id| cx.tcx.hir_fn_decl_by_hir_id(cx.tcx.local_def_id_to_hir_id(id)));
             Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
         },
         ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).instantiate(cx.tcx, subs), Some(id))),
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 37f72966892..3bf518f7fe7 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -133,8 +133,8 @@ impl<'tcx> Visitor<'tcx> for BindingUsageFinder<'_, 'tcx> {
         ControlFlow::Continue(())
     }
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
     }
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 70910f5bf52..2ac0efd7e39 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -154,8 +154,8 @@ pub fn for_each_expr<'tcx, B, C: Continue>(
         type NestedFilter = nested_filter::OnlyBodies;
         type Result = ControlFlow<B>;
 
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.tcx.hir()
+        fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+            self.tcx
         }
 
         fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> Self::Result {
@@ -296,7 +296,7 @@ where
 
 /// Checks if the given resolved path is used in the given body.
 pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
-    for_each_expr(cx, cx.tcx.hir().body(body).value, |e| {
+    for_each_expr(cx, cx.tcx.hir_body(body).value, |e| {
         if let ExprKind::Path(p) = &e.kind {
             if cx.qpath_res(p, e.hir_id) == res {
                 return ControlFlow::Break(());
@@ -412,8 +412,8 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
         type NestedFilter = nested_filter::OnlyBodies;
         type Result = ControlFlow<()>;
 
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.cx.tcx.hir()
+        fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+            self.cx.tcx
         }
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result {
             match e.kind {
@@ -456,7 +456,7 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
             }
         }
         fn visit_nested_item(&mut self, id: ItemId) -> Self::Result {
-            if let ItemKind::Impl(i) = &self.cx.tcx.hir().item(id).kind
+            if let ItemKind::Impl(i) = &self.cx.tcx.hir_item(id).kind
                 && i.safety.is_unsafe()
             {
                 ControlFlow::Break(())
@@ -477,8 +477,8 @@ pub fn contains_unsafe_block<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>)
     impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
         type Result = ControlFlow<()>;
         type NestedFilter = nested_filter::OnlyBodies;
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.cx.tcx.hir()
+        fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+            self.cx.tcx
         }
 
         fn visit_block(&mut self, b: &'tcx Block<'_>) -> Self::Result {
@@ -544,8 +544,8 @@ pub fn for_each_local_use_after_expr<'tcx, B>(
     }
     impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, B> Visitor<'tcx> for V<'_, 'tcx, F, B> {
         type NestedFilter = nested_filter::OnlyBodies;
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.cx.tcx.hir()
+        fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+            self.cx.tcx
         }
 
         fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
@@ -729,8 +729,8 @@ pub fn for_each_local_assignment<'tcx, B>(
     }
     impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, B> Visitor<'tcx> for V<'_, 'tcx, F, B> {
         type NestedFilter = nested_filter::OnlyBodies;
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.cx.tcx.hir()
+        fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+            self.cx.tcx
         }
 
         fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
index 6bf48d5ba4e..54325f9776c 100644
--- a/src/tools/clippy/tests/ui/author/blocks.stdout
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -42,10 +42,10 @@ if let ExprKind::Block(block, None) = expr.kind
 }
 if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::CoroutineClosure(CoroutineDesugaring::Async), .. } = expr.kind
     && let FnRetTy::DefaultReturn(_) = fn_decl.output
-    && expr1 = &cx.tcx.hir().body(body_id).value
+    && expr1 = &cx.tcx.hir_body(body_id).value
     && let ExprKind::Closure { capture_clause: CaptureBy::Ref, fn_decl: fn_decl1, body: body_id1, closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)), .. } = expr1.kind
     && let FnRetTy::DefaultReturn(_) = fn_decl1.output
-    && expr2 = &cx.tcx.hir().body(body_id1).value
+    && expr2 = &cx.tcx.hir_body(body_id1).value
     && let ExprKind::Block(block, None) = expr2.kind
     && block.stmts.is_empty()
     && let Some(trailing_expr) = block.expr
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
index 66caf382d89..3186d0cbc27 100644
--- a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
+++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
@@ -2,7 +2,7 @@ if let StmtKind::Let(local) = stmt.kind
     && let Some(init) = local.init
     && let ExprKind::Closure { capture_clause: CaptureBy::Ref, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = init.kind
     && let FnRetTy::DefaultReturn(_) = fn_decl.output
-    && expr = &cx.tcx.hir().body(body_id).value
+    && expr = &cx.tcx.hir_body(body_id).value
     && let ExprKind::Block(block, None) = expr.kind
     && block.stmts.len() == 1
     && let StmtKind::Semi(e) = block.stmts[0].kind
diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui/author/repeat.stdout
index 1a608734ada..f2c6b3f807f 100644
--- a/src/tools/clippy/tests/ui/author/repeat.stdout
+++ b/src/tools/clippy/tests/ui/author/repeat.stdout
@@ -2,7 +2,7 @@ if let ExprKind::Repeat(value, length) = expr.kind
     && let ExprKind::Lit(ref lit) = value.kind
     && let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node
     && let ConstArgKind::Anon(anon_const) = length.kind
-    && expr1 = &cx.tcx.hir().body(anon_const.body).value
+    && expr1 = &cx.tcx.hir_body(anon_const.body).value
     && let ExprKind::Lit(ref lit1) = expr1.kind
     && let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node
 {
diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml
index f4dac6e947e..54fe7f6eb5a 100644
--- a/src/tools/error_index_generator/Cargo.toml
+++ b/src/tools/error_index_generator/Cargo.toml
@@ -2,6 +2,7 @@
 name = "error_index_generator"
 version = "0.0.0"
 edition = "2021"
+workspace = "../rustbook"
 
 [dependencies]
 mdbook = { version = "0.4", default-features = false, features = ["search"] }
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
index 51e353e9b22..b717bd53eb1 100644
--- a/src/tools/generate-copyright/src/cargo_metadata.rs
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -11,10 +11,6 @@ pub enum Error {
     Io(#[from] std::io::Error),
     #[error("Failed get output from cargo-metadata: {0:?}")]
     GettingMetadata(#[from] cargo_metadata::Error),
-    #[error("Failed to run cargo vendor: {0:?}")]
-    LaunchingVendor(std::io::Error),
-    #[error("Failed to complete cargo vendor")]
-    RunningVendor,
     #[error("Bad path {0:?} whilst scraping files")]
     Scraping(PathBuf),
 }
@@ -43,25 +39,19 @@ pub struct PackageMetadata {
     pub is_in_libstd: Option<bool>,
 }
 
-/// Use `cargo metadata` and `cargo vendor` to get a list of dependencies and their license data.
+/// Use `cargo metadata` to get a list of dependencies and their license data. License files will
+/// also be pulled from the vendor path (generated by bootstrap).
 ///
-/// This will involve running `cargo vendor` into `vendor_path` so we can
-/// grab the license files.
-///
-/// Any dependency with a path beginning with `root_path` is ignored, as we
-/// assume `reuse` has covered it already.
+/// Any dependency with a path beginning with `root_path` is ignored, as we assume `reuse` has
+/// covered it already.
 pub fn get_metadata_and_notices(
     cargo: &Path,
     vendor_path: &Path,
     root_path: &Path,
-    manifest_paths: &[&Path],
+    manifest_paths: &[PathBuf],
 ) -> Result<BTreeMap<Package, PackageMetadata>, Error> {
     let mut output = get_metadata(cargo, root_path, manifest_paths)?;
 
-    // Now do a cargo-vendor and grab everything
-    println!("Vendoring deps into {}...", vendor_path.display());
-    run_cargo_vendor(cargo, &vendor_path, manifest_paths)?;
-
     // Now for each dependency we found, go and grab any important looking files
     for (package, metadata) in output.iter_mut() {
         load_important_files(package, metadata, &vendor_path)?;
@@ -77,7 +67,7 @@ pub fn get_metadata_and_notices(
 pub fn get_metadata(
     cargo: &Path,
     root_path: &Path,
-    manifest_paths: &[&Path],
+    manifest_paths: &[PathBuf],
 ) -> Result<BTreeMap<Package, PackageMetadata>, Error> {
     let mut output = BTreeMap::new();
     // Look at the metadata for each manifest
@@ -113,28 +103,6 @@ pub fn get_metadata(
     Ok(output)
 }
 
-/// Run cargo-vendor, fetching into the given dir
-fn run_cargo_vendor(cargo: &Path, dest: &Path, manifest_paths: &[&Path]) -> Result<(), Error> {
-    let mut vendor_command = std::process::Command::new(cargo);
-    vendor_command.env("RUSTC_BOOTSTRAP", "1");
-    vendor_command.arg("vendor");
-    vendor_command.arg("--quiet");
-    vendor_command.arg("--versioned-dirs");
-    for manifest_path in manifest_paths {
-        vendor_command.arg("-s");
-        vendor_command.arg(manifest_path);
-    }
-    vendor_command.arg(dest);
-
-    let vendor_status = vendor_command.status().map_err(Error::LaunchingVendor)?;
-
-    if !vendor_status.success() {
-        return Err(Error::RunningVendor);
-    }
-
-    Ok(())
-}
-
 /// Add important files off disk into this dependency.
 ///
 /// Maybe one-day Cargo.toml will contain enough information that we don't need
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index 7a014989e68..79e90d88f44 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -17,29 +17,36 @@ mod cargo_metadata;
 fn main() -> Result<(), Error> {
     let dest_file = env_path("DEST")?;
     let libstd_dest_file = env_path("DEST_LIBSTD")?;
-    let out_dir = env_path("OUT_DIR")?;
+    let src_dir = env_path("SRC_DIR")?;
+    let vendor_dir = env_path("VENDOR_DIR")?;
     let cargo = env_path("CARGO")?;
     let license_metadata = env_path("LICENSE_METADATA")?;
 
-    let root_path = std::path::absolute(".")?;
+    let cargo_manifests = env_string("CARGO_MANIFESTS")?
+        .split(",")
+        .map(|manifest| manifest.into())
+        .collect::<Vec<PathBuf>>();
+    let library_manifests = cargo_manifests
+        .iter()
+        .filter(|path| {
+            if let Ok(stripped) = path.strip_prefix(&src_dir) {
+                stripped.starts_with("library")
+            } else {
+                panic!("manifest {path:?} not relative to source dir {src_dir:?}");
+            }
+        })
+        .cloned()
+        .collect::<Vec<_>>();
 
     // Scan Cargo dependencies
-    let mut collected_cargo_metadata = cargo_metadata::get_metadata_and_notices(
-        &cargo,
-        &out_dir.join("vendor"),
-        &root_path,
-        &[
-            Path::new("./Cargo.toml"),
-            Path::new("./src/tools/cargo/Cargo.toml"),
-            Path::new("./library/Cargo.toml"),
-        ],
-    )?;
+    let mut collected_cargo_metadata =
+        cargo_metadata::get_metadata_and_notices(&cargo, &vendor_dir, &src_dir, &cargo_manifests)?;
 
     let library_collected_cargo_metadata = cargo_metadata::get_metadata_and_notices(
         &cargo,
-        &out_dir.join("library-vendor"),
-        &root_path,
-        &[Path::new("./library/Cargo.toml")],
+        &vendor_dir,
+        &src_dir,
+        &library_manifests,
     )?;
 
     for (key, value) in collected_cargo_metadata.iter_mut() {
@@ -54,7 +61,7 @@ fn main() -> Result<(), Error> {
     let library_collected_tree_metadata = Metadata {
         files: collected_tree_metadata
             .files
-            .trim_clone(&Path::new("./library"), &Path::new("."))
+            .trim_clone(&src_dir.join("library"), &src_dir)
             .unwrap(),
     };
 
@@ -193,6 +200,17 @@ struct License {
     copyright: Vec<String>,
 }
 
+/// Grab an environment variable as string, or fail nicely.
+fn env_string(var: &str) -> Result<String, Error> {
+    match std::env::var(var) {
+        Ok(var) => Ok(var),
+        Err(std::env::VarError::NotUnicode(_)) => {
+            anyhow::bail!("environment variable {var} is not utf-8")
+        }
+        Err(std::env::VarError::NotPresent) => anyhow::bail!("missing environment variable {var}"),
+    }
+}
+
 /// Grab an environment variable as a PathBuf, or fail nicely.
 fn env_path(var: &str) -> Result<PathBuf, Error> {
     if let Some(var) = std::env::var_os(var) {
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 0ea62d4d850..a2a2f28ea71 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-d1fb81e8dd5354ddf7cb334d5a234cab7f64b3bb
+17c1c329a5512d718b67ef6797538b154016cd34
diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
index 782303d5f3f..80dd2f39b42 100644
--- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
+++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
@@ -1,6 +1,8 @@
 
 thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
 unsafe precondition(s) violated: ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap
+
+This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
 thread caused non-unwinding panic. aborting.
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index ec33009239c..81b55712d7f 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -64,7 +64,11 @@ jobs:
         run: |
           rustup update --no-self-update ${{ env.RUST_CHANNEL }}
           rustup default ${{ env.RUST_CHANNEL }}
-          rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src
+          rustup component add --toolchain ${{ env.RUST_CHANNEL }} rust-src
+          # We always use a nightly rustfmt, regardless of channel, because we need
+          # --file-lines.
+          rustup toolchain add nightly --profile minimal
+          rustup component add --toolchain nightly rustfmt
       # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
       - name: Install Rust Problem Matcher
         if: matrix.os == 'ubuntu-latest'
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 98268d8f844..6d7f6042dec 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1514,9 +1514,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.94.0"
+version = "0.95.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fa4333df7b71217edb44a36702cafd2bcfc9850677bdf78b32c9f2c98e5df40"
+checksum = "b40c4e339b71a8f075a829b1acaf32f870a11b466d9b8623d50b0ce33e65af95"
 dependencies = [
  "bitflags 2.7.0",
  "ra-ap-rustc_index",
@@ -1525,9 +1525,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.94.0"
+version = "0.95.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d200275ff3d952cc11108f4dc6a692473659758623d63f2bdcea6104a7f1cec8"
+checksum = "872072e2ba11d11147ebe9fde1608fe7f7d9b5c51dac524af28ee07c6dade468"
 dependencies = [
  "ra-ap-rustc_index_macros",
  "smallvec",
@@ -1535,9 +1535,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.94.0"
+version = "0.95.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06eb63df8c1ce2dcb07647305bed811c9c5ebd157def01a81c1b9479b8592b3b"
+checksum = "ffcd77debcaf2ad690a57c2d041c11eb33fe66869754b2c5f35c52954b46af0c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1546,9 +1546,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.94.0"
+version = "0.95.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7a4d402b2f85650e8c1f78e2e2defc241b03948d6e30d9f5254c9b82755cc4d"
+checksum = "49265cdf8823f8d246e476c79c60bd6e5b551c81ae76e1c8d6a5e0dc73df0bca"
 dependencies = [
  "memchr",
  "unicode-properties",
@@ -1557,9 +1557,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.94.0"
+version = "0.95.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a23a382dbe392beb26360c1a8ce9193155ef74eeac59bcda0fa0a233e047323a"
+checksum = "b3da239fdc971176de0db45cb631d71475b52033a3d0027d91964da7be89eee6"
 dependencies = [
  "ra-ap-rustc_index",
  "ra-ap-rustc_lexer",
@@ -1567,9 +1567,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.94.0"
+version = "0.95.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d746955d67f315ab79767f1d0bbc17fee4f0970d4a00b9ad76bf09cc7d3cd17e"
+checksum = "56057d08fdfa0d95494e461bbdd5d4b3fdb349cca6be05ad7759bc964be1b8d4"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash 2.0.0",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 44c628e8294..924ffb8dd21 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.94", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.94", default-features = false }
-ra-ap-rustc_index = { version = "0.94", default-features = false }
-ra-ap-rustc_abi = { version = "0.94", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.94", default-features = false }
+ra-ap-rustc_lexer = { version = "0.95", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.95", default-features = false }
+ra-ap-rustc_index = { version = "0.95", default-features = false }
+ra-ap-rustc_abi = { version = "0.95", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.95", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index c5bbd4edba9..bec66278772 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -250,6 +250,7 @@ bitflags::bitflags! {
         const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 3;
         const SKIP_ARRAY_DURING_METHOD_DISPATCH = 1 << 4;
         const SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH = 1 << 5;
+        const RUSTC_PAREN_SUGAR = 1 << 6;
     }
 }
 
@@ -294,6 +295,9 @@ impl TraitData {
         if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
             flags |= TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
         }
+        if attrs.by_key(&sym::rustc_paren_sugar).exists() {
+            flags |= TraitFlags::RUSTC_PAREN_SUGAR;
+        }
 
         let mut skip_array_during_method_dispatch =
             attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
index 8fc19854033..5d1834a8642 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
@@ -9,6 +9,7 @@ use hir_expand::name::Name;
 use intern::sym;
 use la_arena::Arena;
 use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
+use rustc_hashes::Hash64;
 use triomphe::Arc;
 use tt::iter::TtElement;
 
@@ -172,7 +173,7 @@ fn parse_repr_tt(tt: &TopSubtree) -> Option<ReprOptions> {
         }
     }
 
-    Some(ReprOptions { int, align: max_align, pack: min_pack, flags, field_shuffle_seed: 0 })
+    Some(ReprOptions { int, align: max_align, pack: min_pack, flags, field_shuffle_seed: Hash64::ZERO })
 }
 
 impl StructData {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs
index 0f73595347b..e9318d146dd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs
@@ -31,9 +31,9 @@ pub mod keys {
 
     use crate::{
         dyn_map::{DynMap, Policy},
-        BlockId, ConstId, EnumId, EnumVariantId, ExternCrateId, FieldId, FunctionId, ImplId,
-        LifetimeParamId, Macro2Id, MacroRulesId, ProcMacroId, StaticId, StructId, TraitAliasId,
-        TraitId, TypeAliasId, TypeOrConstParamId, UnionId, UseId,
+        BlockId, ConstId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FieldId, FunctionId,
+        ImplId, LifetimeParamId, Macro2Id, MacroRulesId, ProcMacroId, StaticId, StructId,
+        TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, UnionId, UseId,
     };
 
     pub type Key<K, V> = crate::dyn_map::Key<AstPtr<K>, V, AstPtrPolicy<K, V>>;
@@ -44,6 +44,7 @@ pub mod keys {
     pub const STATIC: Key<ast::Static, StaticId> = Key::new();
     pub const TYPE_ALIAS: Key<ast::TypeAlias, TypeAliasId> = Key::new();
     pub const IMPL: Key<ast::Impl, ImplId> = Key::new();
+    pub const EXTERN_BLOCK: Key<ast::ExternBlock, ExternBlockId> = Key::new();
     pub const TRAIT: Key<ast::Trait, TraitId> = Key::new();
     pub const TRAIT_ALIAS: Key<ast::TraitAlias, TraitAliasId> = Key::new();
     pub const STRUCT: Key<ast::Struct, StructId> = Key::new();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
index 9df6eaade75..5ff6a7ffe56 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
@@ -112,9 +112,9 @@ pub struct ExpressionStoreSourceMap {
     // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
     // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
     expr_map: FxHashMap<ExprSource, ExprOrPatId>,
-    expr_map_back: ArenaMap<ExprId, ExprSource>,
+    expr_map_back: ArenaMap<ExprId, ExprOrPatSource>,
 
-    pat_map: FxHashMap<PatSource, PatId>,
+    pat_map: FxHashMap<PatSource, ExprOrPatId>,
     pat_map_back: ArenaMap<PatId, ExprOrPatSource>,
 
     label_map: FxHashMap<LabelSource, LabelId>,
@@ -606,12 +606,12 @@ impl Index<TypeRefId> for ExpressionStore {
 impl ExpressionStoreSourceMap {
     pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
         match id {
-            ExprOrPatId::ExprId(id) => self.expr_syntax(id).map(|it| it.map(AstPtr::wrap_left)),
+            ExprOrPatId::ExprId(id) => self.expr_syntax(id),
             ExprOrPatId::PatId(id) => self.pat_syntax(id),
         }
     }
 
-    pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
+    pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprOrPatSource, SyntheticSyntax> {
         self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
     }
 
@@ -633,7 +633,7 @@ impl ExpressionStoreSourceMap {
         self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
     }
 
-    pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
+    pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<ExprOrPatId> {
         self.pat_map.get(&node.map(AstPtr::new)).cloned()
     }
 
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 88f770da02a..6e505a6b112 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
@@ -44,8 +44,8 @@ use crate::{
             FormatPlaceholder, FormatSign, FormatTrait,
         },
         Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
-        Expr, ExprId, Item, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
-        OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
+        Expr, ExprId, Item, Label, LabelId, Literal, MatchArm, Movability, OffsetOf, Pat, PatId,
+        RecordFieldPat, RecordLitField, Statement,
     },
     item_scope::BuiltinShadowMode,
     lang_item::LangItem,
@@ -1784,23 +1784,33 @@ impl ExprCollector<'_> {
                         self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
                             this.collect_pat_opt(expanded_pat, binding_list)
                         });
-                    self.source_map.pat_map.insert(src, pat);
+                    self.source_map.pat_map.insert(src, pat.into());
                     return pat;
                 }
                 None => Pat::Missing,
             },
-            // FIXME: implement in a way that also builds source map and calculates assoc resolutions in type inference.
             ast::Pat::RangePat(p) => {
-                let mut range_part_lower = |p: Option<ast::Pat>| {
-                    p.and_then(|it| match &it {
-                        ast::Pat::LiteralPat(it) => {
-                            Some(Box::new(LiteralOrConst::Literal(pat_literal_to_hir(it)?.0)))
+                let mut range_part_lower = |p: Option<ast::Pat>| -> Option<ExprId> {
+                    p.and_then(|it| {
+                        let ptr = PatPtr::new(&it);
+                        match &it {
+                            ast::Pat::LiteralPat(it) => Some(self.alloc_expr_from_pat(
+                                Expr::Literal(pat_literal_to_hir(it)?.0),
+                                ptr,
+                            )),
+                            ast::Pat::IdentPat(ident) if ident.is_simple_ident() => ident
+                                .name()
+                                .map(|name| name.as_name())
+                                .map(Path::from)
+                                .map(|path| self.alloc_expr_from_pat(Expr::Path(path), ptr)),
+                            ast::Pat::PathPat(p) => p
+                                .path()
+                                .and_then(|path| self.parse_path(path))
+                                .map(|parsed| self.alloc_expr_from_pat(Expr::Path(parsed), ptr)),
+                            // We only need to handle literal, ident (if bare) and path patterns here,
+                            // as any other pattern as a range pattern operand is semantically invalid.
+                            _ => None,
                         }
-                        pat @ (ast::Pat::IdentPat(_) | ast::Pat::PathPat(_)) => {
-                            let subpat = self.collect_pat(pat.clone(), binding_list);
-                            Some(Box::new(LiteralOrConst::Const(subpat)))
-                        }
-                        _ => None,
                     })
                 };
                 let start = range_part_lower(p.start());
@@ -1863,7 +1873,7 @@ impl ExprCollector<'_> {
                             }
                         });
                     if let Some(pat) = pat.left() {
-                        self.source_map.pat_map.insert(src, pat);
+                        self.source_map.pat_map.insert(src, pat.into());
                     }
                     pat
                 }
@@ -2490,7 +2500,7 @@ impl ExprCollector<'_> {
     fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
         let src = self.expander.in_file(ptr);
         let id = self.store.exprs.alloc(expr);
-        self.source_map.expr_map_back.insert(id, src);
+        self.source_map.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
         self.source_map.expr_map.insert(src, id.into());
         id
     }
@@ -2502,7 +2512,7 @@ impl ExprCollector<'_> {
     fn alloc_expr_desugared_with_ptr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
         let src = self.expander.in_file(ptr);
         let id = self.store.exprs.alloc(expr);
-        self.source_map.expr_map_back.insert(id, src);
+        self.source_map.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
         // We intentionally don't fill this as it could overwrite a non-desugared entry
         // self.source_map.expr_map.insert(src, id);
         id
@@ -2526,11 +2536,20 @@ impl ExprCollector<'_> {
         self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_left));
         id
     }
+
+    fn alloc_expr_from_pat(&mut self, expr: Expr, ptr: PatPtr) -> ExprId {
+        let src = self.expander.in_file(ptr);
+        let id = self.store.exprs.alloc(expr);
+        self.source_map.pat_map.insert(src, id.into());
+        self.source_map.expr_map_back.insert(id, src.map(AstPtr::wrap_right));
+        id
+    }
+
     fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
         let src = self.expander.in_file(ptr);
         let id = self.store.pats.alloc(pat);
         self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_right));
-        self.source_map.pat_map.insert(src, id);
+        self.source_map.pat_map.insert(src, id.into());
         id
     }
     // FIXME: desugared pats don't have ptr, that's wrong and should be fixed somehow.
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 6a0b1e51979..82ad756dc2c 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
@@ -6,10 +6,7 @@ use itertools::Itertools;
 use span::Edition;
 
 use crate::{
-    hir::{
-        Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst, Movability,
-        Statement,
-    },
+    hir::{Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement},
     pretty::{print_generic_args, print_path, print_type_ref},
 };
 
@@ -656,11 +653,11 @@ impl Printer<'_> {
             }
             Pat::Range { start, end } => {
                 if let Some(start) = start {
-                    self.print_literal_or_const(start);
+                    self.print_expr(*start);
                 }
                 w!(self, "..=");
                 if let Some(end) = end {
-                    self.print_literal_or_const(end);
+                    self.print_expr(*end);
                 }
             }
             Pat::Slice { prefix, slice, suffix } => {
@@ -757,13 +754,6 @@ impl Printer<'_> {
         }
     }
 
-    fn print_literal_or_const(&mut self, literal_or_const: &LiteralOrConst) {
-        match literal_or_const {
-            LiteralOrConst::Literal(l) => self.print_literal(l),
-            LiteralOrConst::Const(c) => self.print_pat(*c),
-        }
-    }
-
     fn print_literal(&mut self, literal: &Literal) {
         match literal {
             Literal::String(it) => w!(self, "{:?}", it),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests.rs
index 9bf1ddb4793..16bf46d3e3f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests.rs
@@ -1,11 +1,10 @@
 mod block;
 
+use crate::{hir::MatchArm, test_db::TestDB, ModuleDefId};
 use expect_test::{expect, Expect};
 use la_arena::RawIdx;
 use test_fixture::WithFixture;
 
-use crate::{test_db::TestDB, ModuleDefId};
-
 use super::*;
 
 fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) {
@@ -460,3 +459,45 @@ async fn foo(a: (), b: i32) -> u32 {
     expect!["fn foo(�: (), �: i32) -> impl ::core::future::Future::<Output = u32> �"]
         .assert_eq(&printed);
 }
+
+#[test]
+fn range_bounds_are_hir_exprs() {
+    let (_, body, _) = lower(
+        r#"
+pub const L: i32 = 6;
+mod x {
+    pub const R: i32 = 100;
+}
+const fn f(x: i32) -> i32 {
+    match x {
+        -1..=5 => x * 10,
+        L..=x::R => x * 100,
+        _ => x,
+    }
+}"#,
+    );
+
+    let mtch_arms = body
+        .exprs
+        .iter()
+        .find_map(|(_, expr)| {
+            if let Expr::Match { arms, .. } = expr {
+                return Some(arms);
+            }
+
+            None
+        })
+        .unwrap();
+
+    let MatchArm { pat, .. } = mtch_arms[1];
+    match body.pats[pat] {
+        Pat::Range { start, end } => {
+            let hir_start = &body.exprs[start.unwrap()];
+            let hir_end = &body.exprs[end.unwrap()];
+
+            assert!(matches!(hir_start, Expr::Path { .. }));
+            assert!(matches!(hir_end, Expr::Path { .. }));
+        }
+        _ => {}
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index 0dcddf162b2..494644d8eff 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -55,12 +55,20 @@ impl ExprOrPatId {
         }
     }
 
+    pub fn is_expr(&self) -> bool {
+        matches!(self, Self::ExprId(_))
+    }
+
     pub fn as_pat(self) -> Option<PatId> {
         match self {
             Self::PatId(v) => Some(v),
             _ => None,
         }
     }
+
+    pub fn is_pat(&self) -> bool {
+        matches!(self, Self::PatId(_))
+    }
 }
 stdx::impl_from!(ExprId, PatId for ExprOrPatId);
 
@@ -571,8 +579,8 @@ pub enum Pat {
         ellipsis: bool,
     },
     Range {
-        start: Option<Box<LiteralOrConst>>,
-        end: Option<Box<LiteralOrConst>>,
+        start: Option<ExprId>,
+        end: Option<ExprId>,
     },
     Slice {
         prefix: Box<[PatId]>,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 6137bd34d64..d43776b8a66 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -320,7 +320,7 @@ impl SearchMode {
                     };
                     match m {
                         Some((index, _)) => {
-                            name = &name[index + 1..];
+                            name = name[index..].strip_prefix(|_: char| true).unwrap_or_default();
                             true
                         }
                         None => false,
@@ -1039,4 +1039,22 @@ pub mod fmt {
             "#]],
         );
     }
+
+    #[test]
+    fn unicode_fn_name() {
+        let ra_fixture = r#"
+            //- /main.rs crate:main deps:dep
+            //- /dep.rs crate:dep
+            pub fn あい() {}
+        "#;
+
+        check_search(
+            ra_fixture,
+            "main",
+            Query::new("あ".to_owned()).fuzzy(),
+            expect![[r#"
+            dep::あい (f)
+        "#]],
+        );
+    }
 }
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 65a39c56561..0ca1eb9bcfe 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
@@ -18,8 +18,8 @@ use crate::{
     db::DefDatabase,
     per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem},
     visibility::{Visibility, VisibilityExplicitness},
-    AdtId, BuiltinType, ConstId, ExternCrateId, FxIndexMap, HasModule, ImplId, LocalModuleId,
-    Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
+    AdtId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap, HasModule, ImplId,
+    LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
 };
 
 #[derive(Debug, Default)]
@@ -158,6 +158,8 @@ pub struct ItemScope {
     declarations: Vec<ModuleDefId>,
 
     impls: Vec<ImplId>,
+    #[allow(clippy::box_collection)]
+    extern_blocks: Option<Box<Vec<ExternBlockId>>>,
     unnamed_consts: Vec<ConstId>,
     /// Traits imported via `use Trait as _;`.
     unnamed_trait_imports: FxHashMap<TraitId, Item<()>>,
@@ -319,6 +321,10 @@ impl ItemScope {
         self.extern_crate_decls.iter().copied()
     }
 
+    pub fn extern_blocks(&self) -> impl Iterator<Item = ExternBlockId> + '_ {
+        self.extern_blocks.iter().flat_map(|it| it.iter()).copied()
+    }
+
     pub fn use_decls(&self) -> impl ExactSizeIterator<Item = UseId> + '_ {
         self.use_decls.iter().copied()
     }
@@ -469,6 +475,10 @@ impl ItemScope {
         self.impls.push(imp);
     }
 
+    pub(crate) fn define_extern_block(&mut self, extern_block: ExternBlockId) {
+        self.extern_blocks.get_or_insert_default().push(extern_block);
+    }
+
     pub(crate) fn define_extern_crate_decl(&mut self, extern_crate: ExternCrateId) {
         self.extern_crate_decls.push(extern_crate);
     }
@@ -806,7 +816,11 @@ impl ItemScope {
             use_imports_types,
             use_imports_macros,
             macro_invocations,
+            extern_blocks,
         } = self;
+        if let Some(it) = extern_blocks {
+            it.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/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index c8efd904320..9c947df35e9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -18,9 +18,15 @@ extern crate ra_ap_rustc_parse_format as rustc_parse_format;
 #[cfg(feature = "in-rust-tree")]
 extern crate rustc_abi;
 
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_hashes;
+
 #[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_abi as rustc_abi;
 
+#[cfg(not(feature = "in-rust-tree"))]
+extern crate ra_ap_rustc_hashes as rustc_hashes;
+
 pub mod db;
 
 pub mod attr;
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 70e3e1ed4e9..a43c0eb9d70 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
@@ -5,7 +5,7 @@
 //! in-memory macros.
 use expect_test::expect;
 
-use crate::macro_expansion_tests::check;
+use crate::macro_expansion_tests::{check, check_errors};
 
 #[test]
 fn attribute_macro_attr_censoring() {
@@ -216,3 +216,21 @@ struct S;
 #[doc = "doc attr"] struct S;"##]],
     );
 }
+
+#[test]
+fn cfg_evaluated_before_attr_macros() {
+    check_errors(
+        r#"
+//- proc_macros: disallow_cfg
+
+use proc_macros::disallow_cfg;
+
+#[disallow_cfg] #[cfg(false)] fn foo() {}
+// True cfg are kept.
+// #[disallow_cfg] #[cfg(true)] fn bar() {}
+#[disallow_cfg] #[cfg_attr(false, inline)] fn baz() {}
+#[disallow_cfg] #[cfg_attr(true, inline)] fn qux() {}
+    "#,
+        expect![[r#""#]],
+    );
+}
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 06276335b71..254c1379917 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
@@ -1759,16 +1759,20 @@ impl ModCollector<'_, '_> {
                         );
                     }
                 }
-                ModItem::ExternBlock(block) => self.collect(
-                    &self.item_tree[block].children,
-                    ItemContainerId::ExternBlockId(
-                        ExternBlockLoc {
-                            container: module,
-                            id: ItemTreeId::new(self.tree_id, block),
-                        }
-                        .intern(db),
-                    ),
-                ),
+                ModItem::ExternBlock(block) => {
+                    let extern_block_id = ExternBlockLoc {
+                        container: module,
+                        id: ItemTreeId::new(self.tree_id, block),
+                    }
+                    .intern(db);
+                    self.def_collector.def_map.modules[self.module_id]
+                        .scope
+                        .define_extern_block(extern_block_id);
+                    self.collect(
+                        &self.item_tree[block].children,
+                        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),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
index e59c37104dd..e6c2504d07a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -173,10 +173,7 @@ impl Path {
                 segments: path.mod_path().segments(),
                 generic_args: Some(path.generic_args()),
             },
-            Path::LangItem(_, seg) => PathSegments {
-                segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)),
-                generic_args: None,
-            },
+            Path::LangItem(_, seg) => PathSegments { segments: seg.as_slice(), generic_args: None },
         }
     }
 
@@ -240,6 +237,11 @@ pub struct PathSegment<'a> {
     pub args_and_bindings: Option<&'a GenericArgs>,
 }
 
+impl PathSegment<'_> {
+    pub const MISSING: PathSegment<'static> =
+        PathSegment { name: &Name::missing(), args_and_bindings: None };
+}
+
 #[derive(Debug, Clone, Copy)]
 pub struct PathSegments<'a> {
     segments: &'a [Name],
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 7e13ae2f7a1..9dfb6e3cc4b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -327,8 +327,9 @@ impl Resolver {
                     | LangItemTarget::ImplDef(_)
                     | LangItemTarget::Static(_) => return None,
                 };
+                // Remaining segments start from 0 because lang paths have no segments other than the remaining.
                 return Some((
-                    ResolveValueResult::Partial(type_ns, 1, None),
+                    ResolveValueResult::Partial(type_ns, 0, None),
                     ResolvePathResultPrefixInfo::default(),
                 ));
             }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs
index 01a3103af82..626a82ae08e 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs
@@ -201,9 +201,6 @@ pub(crate) fn process_cfg_attrs(
         MacroDefKind::BuiltInAttr(_, expander) => expander.is_derive(),
         _ => false,
     };
-    if !is_derive {
-        return None;
-    }
     let mut remove = FxHashSet::default();
 
     let item = ast::Item::cast(node.clone())?;
@@ -220,28 +217,43 @@ pub(crate) fn process_cfg_attrs(
             }
         }
     }
-    match item {
-        ast::Item::Struct(it) => match it.field_list()? {
-            ast::FieldList::RecordFieldList(fields) => {
-                process_has_attrs_with_possible_comma(db, fields.fields(), loc.krate, &mut remove)?;
+
+    if is_derive {
+        // Only derives get their code cfg-clean, normal attribute macros process only the cfg at their level
+        // (cfg_attr is handled above, cfg is handled in the def map).
+        match item {
+            ast::Item::Struct(it) => match it.field_list()? {
+                ast::FieldList::RecordFieldList(fields) => {
+                    process_has_attrs_with_possible_comma(
+                        db,
+                        fields.fields(),
+                        loc.krate,
+                        &mut remove,
+                    )?;
+                }
+                ast::FieldList::TupleFieldList(fields) => {
+                    process_has_attrs_with_possible_comma(
+                        db,
+                        fields.fields(),
+                        loc.krate,
+                        &mut remove,
+                    )?;
+                }
+            },
+            ast::Item::Enum(it) => {
+                process_enum(db, it.variant_list()?, loc.krate, &mut remove)?;
             }
-            ast::FieldList::TupleFieldList(fields) => {
-                process_has_attrs_with_possible_comma(db, fields.fields(), loc.krate, &mut remove)?;
+            ast::Item::Union(it) => {
+                process_has_attrs_with_possible_comma(
+                    db,
+                    it.record_field_list()?.fields(),
+                    loc.krate,
+                    &mut remove,
+                )?;
             }
-        },
-        ast::Item::Enum(it) => {
-            process_enum(db, it.variant_list()?, loc.krate, &mut remove)?;
-        }
-        ast::Item::Union(it) => {
-            process_has_attrs_with_possible_comma(
-                db,
-                it.record_field_list()?.fields(),
-                loc.krate,
-                &mut remove,
-            )?;
+            // FIXME: Implement for other items if necessary. As we do not support #[cfg_eval] yet, we do not need to implement it for now
+            _ => {}
         }
-        // FIXME: Implement for other items if necessary. As we do not support #[cfg_eval] yet, we do not need to implement it for now
-        _ => {}
     }
     Some(remove)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 21e5fb5ef9e..0758bd4515e 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -142,8 +142,8 @@ impl Name {
     /// Ideally, we want a `gensym` semantics for missing names -- each missing
     /// name is equal only to itself. It's not clear how to implement this in
     /// salsa though, so we punt on that bit for a moment.
-    pub fn missing() -> Name {
-        Name { symbol: sym::MISSING_NAME.clone(), ctx: () }
+    pub const fn missing() -> Name {
+        Name { symbol: sym::consts::MISSING_NAME, ctx: () }
     }
 
     /// Returns true if this is a fake name for things missing in the source code. See
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 c8ff6cba3dd..6d4753ea389 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -768,23 +768,21 @@ pub(crate) fn adt_datum_query(
         phantom_data,
     };
 
-    // this slows down rust-analyzer by quite a bit unfortunately, so enabling this is currently not worth it
-    let _variant_id_to_fields = |id: VariantId| {
+    let variant_id_to_fields = |id: VariantId| {
         let variant_data = &id.variant_data(db.upcast());
-        let fields = if variant_data.fields().is_empty() {
+        let fields = if variant_data.fields().is_empty() || bound_vars_subst.is_empty(Interner) {
             vec![]
         } else {
-            let field_types = db.field_types(id);
-            variant_data
-                .fields()
-                .iter()
-                .map(|(idx, _)| field_types[idx].clone().substitute(Interner, &bound_vars_subst))
-                .filter(|it| !it.contains_unknown())
-                .collect()
+            // HACK: provide full struct type info slows down rust-analyzer by quite a bit unfortunately,
+            // so we trick chalk into thinking that our struct impl Unsize
+            if let Some(ty) = bound_vars_subst.at(Interner, 0).ty(Interner) {
+                vec![ty.clone()]
+            } else {
+                vec![]
+            }
         };
         rust_ir::AdtVariantDatum { fields }
     };
-    let variant_id_to_fields = |_: VariantId| rust_ir::AdtVariantDatum { fields: vec![] };
 
     let (kind, variants) = match adt_id {
         hir_def::AdtId::StructId(id) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 0b5f1319243..59aaf85164a 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
@@ -440,7 +440,9 @@ impl ExprValidator {
                             return;
                         };
                         let root = source_ptr.file_syntax(db.upcast());
-                        let ast::Expr::IfExpr(if_expr) = source_ptr.value.to_node(&root) else {
+                        let either::Left(ast::Expr::IfExpr(if_expr)) =
+                            source_ptr.value.to_node(&root)
+                        else {
                             return;
                         };
                         let mut top_if_expr = if_expr;
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 2b854310a15..3312da470c0 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
@@ -95,7 +95,7 @@ impl<'db> MatchCheckCtx<'db> {
 
         let place_validity = PlaceValidity::from_bool(known_valid_scrutinee.unwrap_or(true));
         // Measured to take ~100ms on modern hardware.
-        let complexity_limit = Some(500000);
+        let complexity_limit = 500000;
         compute_match_usefulness(self, arms, scrut_ty, place_validity, complexity_limit)
     }
 
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 617ebba8811..0cb7002f446 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -16,7 +16,7 @@
 pub(crate) mod cast;
 pub(crate) mod closure;
 mod coerce;
-mod diagnostics;
+pub(crate) mod diagnostics;
 mod expr;
 mod mutability;
 mod pat;
@@ -236,7 +236,7 @@ pub enum InferenceDiagnostic {
         name: Name,
         /// Contains the type the field resolves to
         field_with_same_name: Option<Ty>,
-        assoc_func_with_same_name: Option<AssocItemId>,
+        assoc_func_with_same_name: Option<FunctionId>,
     },
     UnresolvedAssocItem {
         id: ExprOrPatId,
@@ -1239,7 +1239,29 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) {
-        self.result.expr_adjustments.insert(expr, adjustments);
+        if adjustments.is_empty() {
+            return;
+        }
+        match self.result.expr_adjustments.entry(expr) {
+            std::collections::hash_map::Entry::Occupied(mut entry) => {
+                match (&mut entry.get_mut()[..], &adjustments[..]) {
+                    (
+                        [Adjustment { kind: Adjust::NeverToAny, target }],
+                        [.., Adjustment { target: new_target, .. }],
+                    ) => {
+                        // NeverToAny coercion can target any type, so instead of adding a new
+                        // adjustment on top we can change the target.
+                        *target = new_target.clone();
+                    }
+                    _ => {
+                        *entry.get_mut() = adjustments;
+                    }
+                }
+            }
+            std::collections::hash_map::Entry::Vacant(entry) => {
+                entry.insert(adjustments);
+            }
+        }
     }
 
     fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
@@ -1480,21 +1502,22 @@ impl<'a> InferenceContext<'a> {
             &self.diagnostics,
             InferenceTyDiagnosticSource::Body,
         );
+        let mut path_ctx = ctx.at_path(path, node);
         let (resolution, unresolved) = if value_ns {
-            let Some(res) = ctx.resolve_path_in_value_ns(path, node, HygieneId::ROOT) else {
+            let Some(res) = path_ctx.resolve_path_in_value_ns(HygieneId::ROOT) else {
                 return (self.err_ty(), None);
             };
             match res {
                 ResolveValueResult::ValueNs(value, _) => match value {
                     ValueNs::EnumVariantId(var) => {
-                        let substs = ctx.substs_from_path(path, var.into(), true);
+                        let substs = path_ctx.substs_from_path(var.into(), true);
                         drop(ctx);
                         let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
                         let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
                         return (ty, Some(var.into()));
                     }
                     ValueNs::StructId(strukt) => {
-                        let substs = ctx.substs_from_path(path, strukt.into(), true);
+                        let substs = path_ctx.substs_from_path(strukt.into(), true);
                         drop(ctx);
                         let ty = self.db.ty(strukt.into());
                         let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
@@ -1509,7 +1532,7 @@ impl<'a> InferenceContext<'a> {
                 ResolveValueResult::Partial(typens, unresolved, _) => (typens, Some(unresolved)),
             }
         } else {
-            match ctx.resolve_path_in_type_ns(path, node) {
+            match path_ctx.resolve_path_in_type_ns() {
                 Some((it, idx)) => (it, idx),
                 None => return (self.err_ty(), None),
             }
@@ -1520,21 +1543,21 @@ impl<'a> InferenceContext<'a> {
         };
         return match resolution {
             TypeNs::AdtId(AdtId::StructId(strukt)) => {
-                let substs = ctx.substs_from_path(path, strukt.into(), true);
+                let substs = path_ctx.substs_from_path(strukt.into(), true);
                 drop(ctx);
                 let ty = self.db.ty(strukt.into());
                 let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
                 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
             }
             TypeNs::AdtId(AdtId::UnionId(u)) => {
-                let substs = ctx.substs_from_path(path, u.into(), true);
+                let substs = path_ctx.substs_from_path(u.into(), true);
                 drop(ctx);
                 let ty = self.db.ty(u.into());
                 let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
                 forbid_unresolved_segments((ty, Some(u.into())), unresolved)
             }
             TypeNs::EnumVariantId(var) => {
-                let substs = ctx.substs_from_path(path, var.into(), true);
+                let substs = path_ctx.substs_from_path(var.into(), true);
                 drop(ctx);
                 let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
                 let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
@@ -1545,31 +1568,32 @@ impl<'a> InferenceContext<'a> {
                 let substs = generics.placeholder_subst(self.db);
                 let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
 
-                let Some(mut remaining_idx) = unresolved else {
+                let Some(remaining_idx) = unresolved else {
                     drop(ctx);
                     return self.resolve_variant_on_alias(ty, None, mod_path);
                 };
 
                 let mut remaining_segments = path.segments().skip(remaining_idx);
 
+                if remaining_segments.len() >= 2 {
+                    path_ctx.ignore_last_segment();
+                }
+
                 // We need to try resolving unresolved segments one by one because each may resolve
                 // to a projection, which `TyLoweringContext` cannot handle on its own.
                 let mut tried_resolving_once = false;
-                while !remaining_segments.is_empty() {
-                    let resolved_segment = path.segments().get(remaining_idx - 1).unwrap();
-                    let current_segment = remaining_segments.take(1);
-
+                while let Some(current_segment) = remaining_segments.first() {
                     // 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_data(id);
-                        let name = current_segment.first().unwrap().name;
-                        if let Some(variant) = enum_data.variant(name) {
+                        if let Some(variant) = enum_data.variant(current_segment.name) {
                             return if remaining_segments.len() == 1 {
                                 (ty, Some(variant.into()))
                             } else {
                                 // We still have unresolved paths, but enum variants never have
                                 // associated types!
+                                // FIXME: Report an error.
                                 (self.err_ty(), None)
                             };
                         }
@@ -1578,23 +1602,13 @@ impl<'a> InferenceContext<'a> {
                     if tried_resolving_once {
                         // FIXME: with `inherent_associated_types` this is allowed, but our `lower_partly_resolved_path()`
                         // will need to be updated to err at the correct segment.
-                        //
-                        // We need to stop here because otherwise the segment index passed to `lower_partly_resolved_path()`
-                        // will be incorrect, and that can mess up error reporting.
                         break;
                     }
 
                     // `lower_partly_resolved_path()` returns `None` as type namespace unless
                     // `remaining_segments` is empty, which is never the case here. We don't know
                     // which namespace the new `ty` is in until normalized anyway.
-                    (ty, _) = ctx.lower_partly_resolved_path(
-                        node,
-                        resolution,
-                        resolved_segment,
-                        current_segment,
-                        (remaining_idx - 1) as u32,
-                        false,
-                    );
+                    (ty, _) = path_ctx.lower_partly_resolved_path(resolution, false);
                     tried_resolving_once = true;
 
                     ty = self.table.insert_type_vars(ty);
@@ -1604,8 +1618,6 @@ impl<'a> InferenceContext<'a> {
                         return (self.err_ty(), None);
                     }
 
-                    // FIXME(inherent_associated_types): update `resolution` based on `ty` here.
-                    remaining_idx += 1;
                     remaining_segments = remaining_segments.skip(1);
                 }
                 drop(ctx);
@@ -1621,12 +1633,7 @@ impl<'a> InferenceContext<'a> {
                 (ty, variant)
             }
             TypeNs::TypeAliasId(it) => {
-                let resolved_seg = match unresolved {
-                    None => path.segments().last().unwrap(),
-                    Some(n) => path.segments().get(path.segments().len() - n - 1).unwrap(),
-                };
-                let substs =
-                    ctx.substs_from_path_segment(resolved_seg, Some(it.into()), true, None);
+                let substs = path_ctx.substs_from_path_segment(it.into(), true, None);
                 drop(ctx);
                 let ty = self.db.ty(it.into());
                 let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
index 956d4de0715..acd86b1f3ed 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
@@ -163,10 +163,27 @@ impl CoerceMany {
         // type is a type variable and the new one is `!`, trying it the other
         // way around first would mean we make the type variable `!`, instead of
         // just marking it as possibly diverging.
-        if let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) {
-            self.final_ty = Some(res);
-        } else if let Ok(res) = ctx.coerce(expr, &self.merged_ty(), &expr_ty, CoerceNever::Yes) {
+        //
+        // - [Comment from rustc](https://github.com/rust-lang/rust/blob/5ff18d0eaefd1bd9ab8ec33dab2404a44e7631ed/compiler/rustc_hir_typeck/src/coercion.rs#L1334-L1335)
+        // First try to coerce the new expression to the type of the previous ones,
+        // but only if the new expression has no coercion already applied to it.
+        if expr.is_none_or(|expr| !ctx.result.expr_adjustments.contains_key(&expr)) {
+            if let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) {
+                self.final_ty = Some(res);
+                if let Some(expr) = expr {
+                    self.expressions.push(expr);
+                }
+                return;
+            }
+        }
+
+        if let Ok((adjustments, res)) =
+            ctx.coerce_inner(&self.merged_ty(), &expr_ty, CoerceNever::Yes)
+        {
             self.final_ty = Some(res);
+            for &e in &self.expressions {
+                ctx.write_expr_adj(e, adjustments.clone());
+            }
         } else {
             match cause {
                 CoercionCause::Expr(id) => {
@@ -244,14 +261,23 @@ impl InferenceContext<'_> {
         // between places and values.
         coerce_never: CoerceNever,
     ) -> Result<Ty, TypeError> {
-        let from_ty = self.resolve_ty_shallow(from_ty);
-        let to_ty = self.resolve_ty_shallow(to_ty);
-        let (adjustments, ty) = self.table.coerce(&from_ty, &to_ty, coerce_never)?;
+        let (adjustments, ty) = self.coerce_inner(from_ty, to_ty, coerce_never)?;
         if let Some(expr) = expr {
             self.write_expr_adj(expr, adjustments);
         }
         Ok(ty)
     }
+
+    fn coerce_inner(
+        &mut self,
+        from_ty: &Ty,
+        to_ty: &Ty,
+        coerce_never: CoerceNever,
+    ) -> Result<(Vec<Adjustment>, Ty), TypeError> {
+        let from_ty = self.resolve_ty_shallow(from_ty);
+        let to_ty = self.resolve_ty_shallow(to_ty);
+        self.table.coerce(&from_ty, &to_ty, coerce_never)
+    }
 }
 
 impl InferenceTable<'_> {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
index b85378531ad..e4f5b5ed378 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
@@ -5,16 +5,14 @@
 use std::cell::RefCell;
 use std::ops::{Deref, DerefMut};
 
-use hir_def::expr_store::HygieneId;
-use hir_def::hir::ExprOrPatId;
-use hir_def::path::{Path, PathSegment, PathSegments};
-use hir_def::resolver::{ResolveValueResult, Resolver, TypeNs};
-use hir_def::type_ref::TypesMap;
-use hir_def::TypeOwnerId;
-
-use crate::db::HirDatabase;
+use either::Either;
+use hir_def::{hir::ExprOrPatId, path::Path, resolver::Resolver, type_ref::TypesMap, TypeOwnerId};
+use la_arena::{Idx, RawIdx};
+
 use crate::{
-    InferenceDiagnostic, InferenceTyDiagnosticSource, Ty, TyLoweringContext, TyLoweringDiagnostic,
+    db::HirDatabase,
+    lower::path::{PathDiagnosticCallback, PathLoweringContext},
+    InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringContext, TyLoweringDiagnostic,
 };
 
 // Unfortunately, this struct needs to use interior mutability (but we encapsulate it)
@@ -44,6 +42,11 @@ impl Diagnostics {
     }
 }
 
+pub(crate) struct PathDiagnosticCallbackData<'a> {
+    node: ExprOrPatId,
+    diagnostics: &'a Diagnostics,
+}
+
 pub(super) struct InferenceTyLoweringContext<'a> {
     ctx: TyLoweringContext<'a>,
     diagnostics: &'a Diagnostics,
@@ -51,6 +54,7 @@ pub(super) struct InferenceTyLoweringContext<'a> {
 }
 
 impl<'a> InferenceTyLoweringContext<'a> {
+    #[inline]
     pub(super) fn new(
         db: &'a dyn HirDatabase,
         resolver: &'a Resolver,
@@ -62,65 +66,62 @@ impl<'a> InferenceTyLoweringContext<'a> {
         Self { ctx: TyLoweringContext::new(db, resolver, types_map, owner), diagnostics, source }
     }
 
-    pub(super) fn resolve_path_in_type_ns(
-        &mut self,
-        path: &Path,
+    #[inline]
+    pub(super) fn at_path<'b>(
+        &'b mut self,
+        path: &'b Path,
         node: ExprOrPatId,
-    ) -> Option<(TypeNs, Option<usize>)> {
-        let diagnostics = self.diagnostics;
-        self.ctx.resolve_path_in_type_ns(path, &mut |_, diag| {
-            diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag })
-        })
+    ) -> PathLoweringContext<'b, 'a> {
+        let on_diagnostic = PathDiagnosticCallback {
+            data: Either::Right(PathDiagnosticCallbackData { diagnostics: self.diagnostics, node }),
+            callback: |data, _, diag| {
+                let data = data.as_ref().right().unwrap();
+                data.diagnostics
+                    .push(InferenceDiagnostic::PathDiagnostic { node: data.node, diag });
+            },
+        };
+        PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
     }
 
-    pub(super) fn resolve_path_in_value_ns(
-        &mut self,
-        path: &Path,
-        node: ExprOrPatId,
-        hygiene_id: HygieneId,
-    ) -> Option<ResolveValueResult> {
-        let diagnostics = self.diagnostics;
-        self.ctx.resolve_path_in_value_ns(path, hygiene_id, &mut |_, diag| {
-            diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag })
-        })
+    #[inline]
+    pub(super) fn at_path_forget_diagnostics<'b>(
+        &'b mut self,
+        path: &'b Path,
+    ) -> PathLoweringContext<'b, 'a> {
+        let on_diagnostic = PathDiagnosticCallback {
+            data: Either::Right(PathDiagnosticCallbackData {
+                diagnostics: self.diagnostics,
+                node: ExprOrPatId::ExprId(Idx::from_raw(RawIdx::from_u32(0))),
+            }),
+            callback: |_data, _, _diag| {},
+        };
+        PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
     }
 
-    pub(super) fn lower_partly_resolved_path(
-        &mut self,
-        node: ExprOrPatId,
-        resolution: TypeNs,
-        resolved_segment: PathSegment<'_>,
-        remaining_segments: PathSegments<'_>,
-        resolved_segment_idx: u32,
-        infer_args: bool,
-    ) -> (Ty, Option<TypeNs>) {
-        let diagnostics = self.diagnostics;
-        self.ctx.lower_partly_resolved_path(
-            resolution,
-            resolved_segment,
-            remaining_segments,
-            resolved_segment_idx,
-            infer_args,
-            &mut |_, diag| diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag }),
-        )
+    #[inline]
+    pub(super) fn forget_diagnostics(&mut self) {
+        self.ctx.diagnostics.clear();
     }
 }
 
 impl<'a> Deref for InferenceTyLoweringContext<'a> {
     type Target = TyLoweringContext<'a>;
 
+    #[inline]
     fn deref(&self) -> &Self::Target {
         &self.ctx
     }
 }
 
 impl DerefMut for InferenceTyLoweringContext<'_> {
+    #[inline]
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.ctx
     }
 }
 
 impl Drop for InferenceTyLoweringContext<'_> {
+    #[inline]
     fn drop(&mut self) {
         self.diagnostics
             .push_ty_diagnostics(self.source, std::mem::take(&mut self.ctx.diagnostics));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 86e5afdb509..80e3ca1fa28 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -489,78 +489,7 @@ impl InferenceContext<'_> {
 
                 ty
             }
-            Expr::Call { callee, args, .. } => {
-                let callee_ty = self.infer_expr(*callee, &Expectation::none(), ExprIsRead::Yes);
-                let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false, true);
-                let (res, derefed_callee) = loop {
-                    let Some((callee_deref_ty, _)) = derefs.next() else {
-                        break (None, callee_ty.clone());
-                    };
-                    if let Some(res) = derefs.table.callable_sig(&callee_deref_ty, args.len()) {
-                        break (Some(res), callee_deref_ty);
-                    }
-                };
-                // if the function is unresolved, we use is_varargs=true to
-                // suppress the arg count diagnostic here
-                let is_varargs =
-                    derefed_callee.callable_sig(self.db).is_some_and(|sig| sig.is_varargs)
-                        || res.is_none();
-                let (param_tys, ret_ty) = match res {
-                    Some((func, params, ret_ty)) => {
-                        let mut adjustments = auto_deref_adjust_steps(&derefs);
-                        if let TyKind::Closure(c, _) =
-                            self.table.resolve_completely(callee_ty.clone()).kind(Interner)
-                        {
-                            if let Some(par) = self.current_closure {
-                                self.closure_dependencies.entry(par).or_default().push(*c);
-                            }
-                            self.deferred_closures.entry(*c).or_default().push((
-                                derefed_callee.clone(),
-                                callee_ty.clone(),
-                                params.clone(),
-                                tgt_expr,
-                            ));
-                        }
-                        if let Some(fn_x) = func {
-                            self.write_fn_trait_method_resolution(
-                                fn_x,
-                                &derefed_callee,
-                                &mut adjustments,
-                                &callee_ty,
-                                &params,
-                                tgt_expr,
-                            );
-                        }
-                        self.write_expr_adj(*callee, adjustments);
-                        (params, ret_ty)
-                    }
-                    None => {
-                        self.push_diagnostic(InferenceDiagnostic::ExpectedFunction {
-                            call_expr: tgt_expr,
-                            found: callee_ty.clone(),
-                        });
-                        (Vec::new(), self.err_ty())
-                    }
-                };
-                let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args);
-                self.register_obligations_for_call(&callee_ty);
-
-                let expected_inputs = self.expected_inputs_for_expected_output(
-                    expected,
-                    ret_ty.clone(),
-                    param_tys.clone(),
-                );
-
-                self.check_call_arguments(
-                    tgt_expr,
-                    args,
-                    &expected_inputs,
-                    &param_tys,
-                    &indices_to_skip,
-                    is_varargs,
-                );
-                self.normalize_associated_types_in(ret_ty)
-            }
+            Expr::Call { callee, args, .. } => self.infer_call(tgt_expr, *callee, args, expected),
             Expr::MethodCall { receiver, args, method_name, generic_args } => self
                 .infer_method_call(
                     tgt_expr,
@@ -1872,6 +1801,107 @@ impl InferenceContext<'_> {
         }
     }
 
+    fn infer_call(
+        &mut self,
+        tgt_expr: ExprId,
+        callee: ExprId,
+        args: &[ExprId],
+        expected: &Expectation,
+    ) -> Ty {
+        let callee_ty = self.infer_expr(callee, &Expectation::none(), ExprIsRead::Yes);
+        let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false, true);
+        let (res, derefed_callee) = loop {
+            let Some((callee_deref_ty, _)) = derefs.next() else {
+                break (None, callee_ty.clone());
+            };
+            if let Some(res) = derefs.table.callable_sig(&callee_deref_ty, args.len()) {
+                break (Some(res), callee_deref_ty);
+            }
+        };
+        // if the function is unresolved, we use is_varargs=true to
+        // suppress the arg count diagnostic here
+        let is_varargs =
+            derefed_callee.callable_sig(self.db).is_some_and(|sig| sig.is_varargs) || res.is_none();
+        let (param_tys, ret_ty) = match res {
+            Some((func, params, ret_ty)) => {
+                let mut adjustments = auto_deref_adjust_steps(&derefs);
+                if let TyKind::Closure(c, _) =
+                    self.table.resolve_completely(callee_ty.clone()).kind(Interner)
+                {
+                    if let Some(par) = self.current_closure {
+                        self.closure_dependencies.entry(par).or_default().push(*c);
+                    }
+                    self.deferred_closures.entry(*c).or_default().push((
+                        derefed_callee.clone(),
+                        callee_ty.clone(),
+                        params.clone(),
+                        tgt_expr,
+                    ));
+                }
+                if let Some(fn_x) = func {
+                    self.write_fn_trait_method_resolution(
+                        fn_x,
+                        &derefed_callee,
+                        &mut adjustments,
+                        &callee_ty,
+                        &params,
+                        tgt_expr,
+                    );
+                }
+                self.write_expr_adj(callee, adjustments);
+                (params, ret_ty)
+            }
+            None => {
+                self.push_diagnostic(InferenceDiagnostic::ExpectedFunction {
+                    call_expr: tgt_expr,
+                    found: callee_ty.clone(),
+                });
+                (Vec::new(), self.err_ty())
+            }
+        };
+        let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args);
+        self.check_call(
+            tgt_expr,
+            args,
+            callee_ty,
+            &param_tys,
+            ret_ty,
+            &indices_to_skip,
+            is_varargs,
+            expected,
+        )
+    }
+
+    fn check_call(
+        &mut self,
+        tgt_expr: ExprId,
+        args: &[ExprId],
+        callee_ty: Ty,
+        param_tys: &[Ty],
+        ret_ty: Ty,
+        indices_to_skip: &[u32],
+        is_varargs: bool,
+        expected: &Expectation,
+    ) -> Ty {
+        self.register_obligations_for_call(&callee_ty);
+
+        let expected_inputs = self.expected_inputs_for_expected_output(
+            expected,
+            ret_ty.clone(),
+            param_tys.to_owned(),
+        );
+
+        self.check_call_arguments(
+            tgt_expr,
+            args,
+            &expected_inputs,
+            param_tys,
+            indices_to_skip,
+            is_varargs,
+        );
+        self.normalize_associated_types_in(ret_ty)
+    }
+
     fn infer_method_call(
         &mut self,
         tgt_expr: ExprId,
@@ -1892,21 +1922,32 @@ impl InferenceContext<'_> {
             VisibleFromModule::Filter(self.resolver.module()),
             method_name,
         );
-        let (receiver_ty, method_ty, substs) = match resolved {
+        match resolved {
             Some((adjust, func, visible)) => {
-                let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty);
-                let generics = generics(self.db.upcast(), func.into());
-                let substs = self.substs_for_method_call(generics, generic_args);
-                self.write_expr_adj(receiver, adjustments);
-                self.write_method_resolution(tgt_expr, func, substs.clone());
                 if !visible {
                     self.push_diagnostic(InferenceDiagnostic::PrivateAssocItem {
                         id: tgt_expr.into(),
                         item: func.into(),
                     })
                 }
-                (ty, self.db.value_ty(func.into()).unwrap(), substs)
+
+                let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty);
+                self.write_expr_adj(receiver, adjustments);
+
+                let generics = generics(self.db.upcast(), func.into());
+                let substs = self.substs_for_method_call(generics, generic_args);
+                self.write_method_resolution(tgt_expr, func, substs.clone());
+                self.check_method_call(
+                    tgt_expr,
+                    args,
+                    self.db.value_ty(func.into()).expect("we have a function def"),
+                    substs,
+                    ty,
+                    expected,
+                )
             }
+            // Failed to resolve, report diagnostic and try to resolve as call to field access or
+            // assoc function
             None => {
                 let field_with_same_name_exists = match self.lookup_field(&receiver_ty, method_name)
                 {
@@ -1926,12 +1967,11 @@ impl InferenceContext<'_> {
                     VisibleFromModule::Filter(self.resolver.module()),
                     Some(method_name),
                     method_resolution::LookupMode::Path,
-                    |_ty, item, visible| {
-                        if visible {
-                            Some(item)
-                        } else {
-                            None
+                    |_ty, item, visible| match item {
+                        hir_def::AssocItemId::FunctionId(function_id) if visible => {
+                            Some(function_id)
                         }
+                        _ => None,
                     },
                 );
 
@@ -1939,17 +1979,45 @@ impl InferenceContext<'_> {
                     expr: tgt_expr,
                     receiver: receiver_ty.clone(),
                     name: method_name.clone(),
-                    field_with_same_name: field_with_same_name_exists,
+                    field_with_same_name: field_with_same_name_exists.clone(),
                     assoc_func_with_same_name,
                 });
-                (
-                    receiver_ty,
-                    Binders::empty(Interner, self.err_ty()),
-                    Substitution::empty(Interner),
-                )
+
+                let recovered = match assoc_func_with_same_name {
+                    Some(f) => {
+                        let generics = generics(self.db.upcast(), f.into());
+                        let substs = self.substs_for_method_call(generics, generic_args);
+                        let f = self
+                            .db
+                            .value_ty(f.into())
+                            .expect("we have a function def")
+                            .substitute(Interner, &substs);
+                        let sig = f.callable_sig(self.db).expect("we have a function def");
+                        Some((f, sig, true))
+                    }
+                    None => field_with_same_name_exists.and_then(|field_ty| {
+                        let callable_sig = field_ty.callable_sig(self.db)?;
+                        Some((field_ty, callable_sig, false))
+                    }),
+                };
+                match recovered {
+                    Some((callee_ty, sig, strip_first)) => self.check_call(
+                        tgt_expr,
+                        args,
+                        callee_ty,
+                        sig.params().get(strip_first as usize..).unwrap_or(&[]),
+                        sig.ret().clone(),
+                        &[],
+                        true,
+                        expected,
+                    ),
+                    None => {
+                        self.check_call_arguments(tgt_expr, args, &[], &[], &[], true);
+                        self.err_ty()
+                    }
+                }
             }
-        };
-        self.check_method_call(tgt_expr, args, method_ty, substs, receiver_ty, expected)
+        }
     }
 
     fn check_method_call(
@@ -2019,9 +2087,10 @@ impl InferenceContext<'_> {
         expected_inputs: &[Ty],
         param_tys: &[Ty],
         skip_indices: &[u32],
-        is_varargs: bool,
+        ignore_arg_param_mismatch: bool,
     ) {
-        let arg_count_mismatch = args.len() != param_tys.len() + skip_indices.len() && !is_varargs;
+        let arg_count_mismatch =
+            !ignore_arg_param_mismatch && args.len() != param_tys.len() + skip_indices.len();
         if arg_count_mismatch {
             self.push_diagnostic(InferenceDiagnostic::MismatchedArgCount {
                 call_expr: expr,
@@ -2050,7 +2119,7 @@ impl InferenceContext<'_> {
                     continue;
                 }
 
-                while skip_indices.peek().is_some_and(|i| *i < idx as u32) {
+                while skip_indices.peek().is_some_and(|&i| i < idx as u32) {
                     skip_indices.next();
                 }
                 if skip_indices.peek().copied() == Some(idx as u32) {
@@ -2132,8 +2201,8 @@ impl InferenceContext<'_> {
             for kind_id in def_generics.iter_self_id().take(self_params) {
                 let arg = args.peek();
                 let arg = match (kind_id, arg) {
-                    // Lifetimes can be elided.
-                    // Once we have implemented lifetime elision correctly,
+                    // Lifetimes can be inferred.
+                    // Once we have implemented lifetime inference correctly,
                     // this should be handled in a proper way.
                     (
                         GenericParamId::LifetimeParamId(_),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index 5ff22bea34d..db93116f107 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -564,9 +564,10 @@ impl InferenceContext<'_> {
             | Pat::Range { .. }
             | Pat::Slice { .. } => true,
             Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)),
-            Pat::Path(p) => {
-                let v = self.resolve_value_path_inner(p, pat.into());
-                v.is_some_and(|x| !matches!(x.0, hir_def::resolver::ValueNs::ConstId(_)))
+            Pat::Path(path) => {
+                // A const is a reference pattern, but other value ns things aren't (see #16131).
+                let resolved = self.resolve_value_path_inner(path, pat.into(), true);
+                resolved.is_some_and(|it| !matches!(it.0, hir_def::resolver::ValueNs::ConstId(_)))
             }
             Pat::ConstBlock(..) => false,
             Pat::Lit(expr) => !matches!(
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 36ec60a7a2f..6254bc12392 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
@@ -7,7 +7,6 @@ use hir_def::{
     AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup,
 };
 use hir_expand::name::Name;
-use intern::sym;
 use stdx::never;
 
 use crate::{
@@ -41,7 +40,7 @@ impl InferenceContext<'_> {
     }
 
     fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
-        let (value, self_subst) = self.resolve_value_path_inner(path, id)?;
+        let (value, self_subst) = self.resolve_value_path_inner(path, id, false)?;
 
         let value_def: ValueTyDefId = match value {
             ValueNs::FunctionId(it) => it.into(),
@@ -94,7 +93,14 @@ impl InferenceContext<'_> {
             return Some(ValuePathResolution::NonGeneric(ty));
         };
 
-        let substs = self.with_body_ty_lowering(|ctx| ctx.substs_from_path(path, value_def, true));
+        let substs = self.with_body_ty_lowering(|ctx| {
+            let mut path_ctx = ctx.at_path(path, id);
+            let last_segment = path.segments().len().checked_sub(1);
+            if let Some(last_segment) = last_segment {
+                path_ctx.set_current_segment(last_segment)
+            }
+            path_ctx.substs_from_path(value_def, true)
+        });
         let substs = substs.as_slice(Interner);
 
         if let ValueNs::EnumVariantId(_) = value {
@@ -146,6 +152,7 @@ impl InferenceContext<'_> {
         &mut self,
         path: &Path,
         id: ExprOrPatId,
+        no_diagnostics: bool,
     ) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
         // Don't use `self.make_ty()` here as we need `orig_ns`.
         let mut ctx = TyLoweringContext::new(
@@ -156,33 +163,83 @@ impl InferenceContext<'_> {
             &self.diagnostics,
             InferenceTyDiagnosticSource::Body,
         );
+        let mut path_ctx = if no_diagnostics {
+            ctx.at_path_forget_diagnostics(path)
+        } else {
+            ctx.at_path(path, id)
+        };
         let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
             let last = path.segments().last()?;
 
-            let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
+            let (ty, orig_ns) = path_ctx.ty_ctx().lower_ty_ext(type_ref);
             let ty = self.table.insert_type_vars(ty);
             let ty = self.table.normalize_associated_types_in(ty);
 
-            let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
-            let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
-            drop(ctx);
+            path_ctx.ignore_last_segment();
+            let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns);
+            drop_ctx(ctx, no_diagnostics);
             let ty = self.table.insert_type_vars(ty);
             let ty = self.table.normalize_associated_types_in(ty);
             self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
         } else {
             let hygiene = self.body.expr_or_pat_path_hygiene(id);
             // FIXME: report error, unresolved first path segment
-            let value_or_partial = ctx.resolve_path_in_value_ns(path, id, hygiene)?;
-            drop(ctx);
+            let value_or_partial = path_ctx.resolve_path_in_value_ns(hygiene)?;
 
             match value_or_partial {
-                ResolveValueResult::ValueNs(it, _) => (it, None),
-                ResolveValueResult::Partial(def, remaining_index, _) => self
-                    .resolve_assoc_item(id, def, path, remaining_index, id)
-                    .map(|(it, substs)| (it, Some(substs)))?,
+                ResolveValueResult::ValueNs(it, _) => {
+                    drop_ctx(ctx, no_diagnostics);
+                    (it, None)
+                }
+                ResolveValueResult::Partial(def, remaining_index, _) => {
+                    // there may be more intermediate segments between the resolved one and
+                    // the end. Only the last segment needs to be resolved to a value; from
+                    // the segments before that, we need to get either a type or a trait ref.
+
+                    let remaining_segments = path.segments().skip(remaining_index);
+                    let is_before_last = remaining_segments.len() == 1;
+                    let last_segment = remaining_segments
+                        .last()
+                        .expect("there should be at least one segment here");
+
+                    let (resolution, substs) = match (def, is_before_last) {
+                        (TypeNs::TraitId(trait_), true) => {
+                            let self_ty = self.table.new_type_var();
+                            let trait_ref =
+                                path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty);
+                            drop_ctx(ctx, no_diagnostics);
+                            self.resolve_trait_assoc_item(trait_ref, last_segment, id)
+                        }
+                        (def, _) => {
+                            // Either we already have a type (e.g. `Vec::new`), or we have a
+                            // trait but it's not the last segment, so the next segment
+                            // should resolve to an associated type of that trait (e.g. `<T
+                            // as Iterator>::Item::default`)
+                            path_ctx.ignore_last_segment();
+                            let (ty, _) = path_ctx.lower_partly_resolved_path(def, true);
+                            drop_ctx(ctx, no_diagnostics);
+                            if ty.is_unknown() {
+                                return None;
+                            }
+
+                            let ty = self.insert_type_vars(ty);
+                            let ty = self.normalize_associated_types_in(ty);
+
+                            self.resolve_ty_assoc_item(ty, last_segment.name, id)
+                        }
+                    }?;
+                    (resolution, Some(substs))
+                }
             }
         };
-        Some((value, self_subst))
+        return Some((value, self_subst));
+
+        #[inline]
+        fn drop_ctx(mut ctx: TyLoweringContext<'_>, no_diagnostics: bool) {
+            if no_diagnostics {
+                ctx.forget_diagnostics();
+            }
+        }
     }
 
     fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) {
@@ -212,89 +269,6 @@ impl InferenceContext<'_> {
         }
     }
 
-    fn resolve_assoc_item(
-        &mut self,
-        node: ExprOrPatId,
-        def: TypeNs,
-        path: &Path,
-        remaining_index: usize,
-        id: ExprOrPatId,
-    ) -> Option<(ValueNs, Substitution)> {
-        // there may be more intermediate segments between the resolved one and
-        // the end. Only the last segment needs to be resolved to a value; from
-        // the segments before that, we need to get either a type or a trait ref.
-
-        let _d;
-        let (resolved_segment, remaining_segments) = match path {
-            Path::Normal { .. } | Path::BarePath(_) => {
-                assert!(remaining_index < path.segments().len());
-                (
-                    path.segments().get(remaining_index - 1).unwrap(),
-                    path.segments().skip(remaining_index),
-                )
-            }
-            Path::LangItem(..) => (
-                PathSegment {
-                    name: {
-                        _d = Name::new_symbol_root(sym::Unknown.clone());
-                        &_d
-                    },
-                    args_and_bindings: None,
-                },
-                path.segments(),
-            ),
-        };
-        let is_before_last = remaining_segments.len() == 1;
-
-        match (def, is_before_last) {
-            (TypeNs::TraitId(trait_), true) => {
-                let segment =
-                    remaining_segments.last().expect("there should be at least one segment here");
-                let self_ty = self.table.new_type_var();
-                let trait_ref = self.with_body_ty_lowering(|ctx| {
-                    ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty)
-                });
-                self.resolve_trait_assoc_item(trait_ref, segment, id)
-            }
-            (def, _) => {
-                // Either we already have a type (e.g. `Vec::new`), or we have a
-                // trait but it's not the last segment, so the next segment
-                // should resolve to an associated type of that trait (e.g. `<T
-                // as Iterator>::Item::default`)
-                let remaining_segments_for_ty =
-                    remaining_segments.take(remaining_segments.len() - 1);
-                let mut ctx = TyLoweringContext::new(
-                    self.db,
-                    &self.resolver,
-                    &self.body.types,
-                    self.owner.into(),
-                    &self.diagnostics,
-                    InferenceTyDiagnosticSource::Body,
-                );
-                let (ty, _) = ctx.lower_partly_resolved_path(
-                    node,
-                    def,
-                    resolved_segment,
-                    remaining_segments_for_ty,
-                    (remaining_index - 1) as u32,
-                    true,
-                );
-                drop(ctx);
-                if ty.is_unknown() {
-                    return None;
-                }
-
-                let ty = self.insert_type_vars(ty);
-                let ty = self.normalize_associated_types_in(ty);
-
-                let segment =
-                    remaining_segments.last().expect("there should be at least one segment here");
-
-                self.resolve_ty_assoc_item(ty, segment.name, id)
-            }
-        }
-    }
-
     fn resolve_trait_assoc_item(
         &mut self,
         trait_ref: TraitRef,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index 108171586ea..b6f7c44c2ae 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -15,6 +15,7 @@ use hir_def::{
 use la_arena::{Idx, RawIdx};
 use rustc_abi::AddressSpace;
 use rustc_index::{IndexSlice, IndexVec};
+use rustc_hashes::Hash64;
 
 use triomphe::Arc;
 
@@ -197,7 +198,7 @@ fn layout_of_simd_ty(
         align,
         max_repr_align: None,
         unadjusted_abi_align: align.abi,
-        randomization_seed: 0,
+        randomization_seed: Hash64::ZERO,
     }))
 }
 
@@ -314,7 +315,7 @@ pub fn layout_of_ty_query(
                 size,
                 max_repr_align: None,
                 unadjusted_abi_align: element.align.abi,
-                randomization_seed: 0,
+                randomization_seed: Hash64::ZERO,
             }
         }
         TyKind::Slice(element) => {
@@ -328,7 +329,7 @@ pub fn layout_of_ty_query(
                 size: Size::ZERO,
                 max_repr_align: None,
                 unadjusted_abi_align: element.align.abi,
-                randomization_seed: 0,
+                randomization_seed: Hash64::ZERO,
             }
         }
         TyKind::Str => Layout {
@@ -340,7 +341,7 @@ pub fn layout_of_ty_query(
             size: Size::ZERO,
             max_repr_align: None,
             unadjusted_abi_align: dl.i8_align.abi,
-            randomization_seed: 0,
+            randomization_seed: Hash64::ZERO,
         },
         // Potentially-wide pointers.
         TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {
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 55d81875a2b..daddcf0b242 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -12,6 +12,9 @@ extern crate ra_ap_rustc_index as rustc_index;
 #[cfg(feature = "in-rust-tree")]
 extern crate rustc_abi;
 
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_hashes;
+
 #[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_abi as rustc_abi;
 
@@ -21,6 +24,9 @@ extern crate rustc_pattern_analysis;
 #[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis;
 
+#[cfg(not(feature = "in-rust-tree"))]
+extern crate ra_ap_rustc_hashes as rustc_hashes;
+
 mod builder;
 mod chalk_db;
 mod chalk_ext;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index db13e1fd354..af73b5ed9a7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -6,6 +6,7 @@
 //!
 //! This usually involves resolving names, collecting generic arguments etc.
 pub(crate) mod diagnostics;
+pub(crate) mod path;
 
 use std::{
     cell::OnceCell,
@@ -26,29 +27,26 @@ use hir_def::{
     builtin_type::BuiltinType,
     data::{adt::StructKind, TraitFlags},
     expander::Expander,
-    expr_store::HygieneId,
     generics::{
         GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
         WherePredicateTypeTarget,
     },
     lang_item::LangItem,
     nameres::MacroSubNs,
-    path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
-    resolver::{HasResolver, LifetimeNs, ResolveValueResult, Resolver, TypeNs, ValueNs},
+    path::{GenericArg, ModPath, Path, PathKind},
+    resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
     type_ref::{
         ConstRef, LifetimeRef, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound,
         TypeRef, TypeRefId, TypesMap, TypesSourceMap,
     },
     AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
-    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId,
-    LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId,
-    TypeOwnerId, UnionId, VariantId,
+    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, LocalFieldId,
+    Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, UnionId, VariantId,
 };
 use hir_expand::{name::Name, ExpandResult};
 use la_arena::{Arena, ArenaMap};
 use rustc_hash::FxHashSet;
 use rustc_pattern_analysis::Captures;
-use smallvec::SmallVec;
 use stdx::{impl_from, never};
 use syntax::ast;
 use triomphe::{Arc, ThinArc};
@@ -62,18 +60,19 @@ use crate::{
     db::HirDatabase,
     error_lifetime,
     generics::{generics, trait_self_param_idx, Generics},
-    lower::diagnostics::*,
+    lower::{
+        diagnostics::*,
+        path::{PathDiagnosticCallback, PathLoweringContext},
+    },
     make_binders,
     mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk},
-    static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
-    utils::{
-        all_super_trait_refs, associated_type_by_name_including_super_traits, InTypeConstIdMetadata,
-    },
-    AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy,
-    FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
-    LifetimeData, LifetimeOutlives, ParamKind, PolyFnSig, ProgramClause, ProjectionTy,
-    QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitEnvironment, TraitRef,
-    TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
+    static_lifetime, to_chalk_trait_id, to_placeholder_idx,
+    utils::{all_super_trait_refs, InTypeConstIdMetadata},
+    AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy, FnAbi,
+    FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
+    LifetimeData, LifetimeOutlives, ParamKind, PolyFnSig, ProgramClause, QuantifiedWhereClause,
+    QuantifiedWhereClauses, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder,
+    TyKind, WhereClause,
 };
 
 #[derive(Debug, Default)]
@@ -106,6 +105,8 @@ impl ImplTraitLoweringState {
     }
 }
 
+pub(crate) struct PathDiagnosticCallbackData(TypeRefId);
+
 #[derive(Debug)]
 pub struct TyLoweringContext<'a> {
     pub db: &'a dyn HirDatabase,
@@ -527,9 +528,8 @@ impl<'a> TyLoweringContext<'a> {
         if path.segments().len() > 1 {
             return None;
         }
-        let resolution = match self
-            .resolve_path_in_type_ns(path, &mut Self::on_path_diagnostic_callback(type_ref_id))
-        {
+        let mut ctx = self.at_path(PathId::from_type_ref_unchecked(type_ref_id));
+        let resolution = match ctx.resolve_path_in_type_ns() {
             Some((it, None)) => it,
             _ => return None,
         };
@@ -539,409 +539,36 @@ impl<'a> TyLoweringContext<'a> {
         }
     }
 
-    pub(crate) fn lower_ty_relative_path(
-        &mut self,
-        ty: Ty,
-        // We need the original resolution to lower `Self::AssocTy` correctly
-        res: Option<TypeNs>,
-        remaining_segments: PathSegments<'_>,
-    ) -> (Ty, Option<TypeNs>) {
-        match remaining_segments.len() {
-            0 => (ty, res),
-            1 => {
-                // resolve unselected assoc types
-                let segment = remaining_segments.first().unwrap();
-                (self.select_associated_type(res, segment), None)
-            }
-            _ => {
-                // FIXME report error (ambiguous associated type)
-                (TyKind::Error.intern(Interner), None)
-            }
-        }
-    }
-
-    pub(crate) fn lower_partly_resolved_path(
-        &mut self,
-        resolution: TypeNs,
-        resolved_segment: PathSegment<'_>,
-        remaining_segments: PathSegments<'_>,
-        _resolved_segment_idx: u32,
-        infer_args: bool,
-        _on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
-    ) -> (Ty, Option<TypeNs>) {
-        let ty = match resolution {
-            TypeNs::TraitId(trait_) => {
-                let ty = match remaining_segments.len() {
-                    1 => {
-                        let trait_ref = self.lower_trait_ref_from_resolved_path(
-                            trait_,
-                            resolved_segment,
-                            TyKind::Error.intern(Interner),
-                        );
-                        let segment = remaining_segments.first().unwrap();
-                        let found = self
-                            .db
-                            .trait_data(trait_ref.hir_trait_id())
-                            .associated_type_by_name(segment.name);
-
-                        match found {
-                            Some(associated_ty) => {
-                                // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
-                                // generic params. It's inefficient to splice the `Substitution`s, so we may want
-                                // that method to optionally take parent `Substitution` as we already know them at
-                                // this point (`trait_ref.substitution`).
-                                let substitution = self.substs_from_path_segment(
-                                    segment,
-                                    Some(associated_ty.into()),
-                                    false,
-                                    None,
-                                );
-                                let len_self =
-                                    generics(self.db.upcast(), associated_ty.into()).len_self();
-                                let substitution = Substitution::from_iter(
-                                    Interner,
-                                    substitution
-                                        .iter(Interner)
-                                        .take(len_self)
-                                        .chain(trait_ref.substitution.iter(Interner)),
-                                );
-                                TyKind::Alias(AliasTy::Projection(ProjectionTy {
-                                    associated_ty_id: to_assoc_type_id(associated_ty),
-                                    substitution,
-                                }))
-                                .intern(Interner)
-                            }
-                            None => {
-                                // FIXME: report error (associated type not found)
-                                TyKind::Error.intern(Interner)
-                            }
-                        }
-                    }
-                    0 => {
-                        // Trait object type without dyn; this should be handled in upstream. See
-                        // `lower_path()`.
-                        stdx::never!("unexpected fully resolved trait path");
-                        TyKind::Error.intern(Interner)
-                    }
-                    _ => {
-                        // FIXME report error (ambiguous associated type)
-                        TyKind::Error.intern(Interner)
-                    }
-                };
-                return (ty, None);
-            }
-            TypeNs::TraitAliasId(_) => {
-                // FIXME(trait_alias): Implement trait alias.
-                return (TyKind::Error.intern(Interner), None);
-            }
-            TypeNs::GenericParam(param_id) => match self.type_param_mode {
-                ParamLoweringMode::Placeholder => {
-                    TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
-                }
-                ParamLoweringMode::Variable => {
-                    let idx = match self
-                        .generics()
-                        .expect("generics in scope")
-                        .type_or_const_param_idx(param_id.into())
-                    {
-                        None => {
-                            never!("no matching generics");
-                            return (TyKind::Error.intern(Interner), None);
-                        }
-                        Some(idx) => idx,
-                    };
-
-                    TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
-                }
-            }
-            .intern(Interner),
-            TypeNs::SelfType(impl_id) => {
-                let generics = self.generics().expect("impl should have generic param scope");
-
-                match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => {
-                        // `def` can be either impl itself or item within, and we need impl itself
-                        // now.
-                        let generics = generics.parent_or_self();
-                        let subst = generics.placeholder_subst(self.db);
-                        self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
-                    }
-                    ParamLoweringMode::Variable => {
-                        let starting_from = match generics.def() {
-                            GenericDefId::ImplId(_) => 0,
-                            // `def` is an item within impl. We need to substitute `BoundVar`s but
-                            // remember that they are for parent (i.e. impl) generic params so they
-                            // come after our own params.
-                            _ => generics.len_self(),
-                        };
-                        TyBuilder::impl_self_ty(self.db, impl_id)
-                            .fill_with_bound_vars(self.in_binders, starting_from)
-                            .build()
-                    }
-                }
-            }
-            TypeNs::AdtSelfType(adt) => {
-                let generics = generics(self.db.upcast(), adt.into());
-                let substs = match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
-                    ParamLoweringMode::Variable => {
-                        generics.bound_vars_subst(self.db, self.in_binders)
-                    }
-                };
-                self.db.ty(adt.into()).substitute(Interner, &substs)
-            }
-
-            TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args),
-            TypeNs::BuiltinType(it) => {
-                self.lower_path_inner(resolved_segment, it.into(), infer_args)
-            }
-            TypeNs::TypeAliasId(it) => {
-                self.lower_path_inner(resolved_segment, it.into(), infer_args)
-            }
-            // FIXME: report error
-            TypeNs::EnumVariantId(_) => return (TyKind::Error.intern(Interner), None),
-        };
-        self.lower_ty_relative_path(ty, Some(resolution), remaining_segments)
-    }
-
-    fn handle_type_ns_resolution(
-        &mut self,
-        resolution: &TypeNs,
-        resolved_segment: PathSegment<'_>,
-        resolved_segment_idx: usize,
-        on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
-    ) {
-        let mut prohibit_generics_on_resolved = |reason| {
-            if resolved_segment.args_and_bindings.is_some() {
-                on_diagnostic(
-                    self,
-                    PathLoweringDiagnostic::GenericArgsProhibited {
-                        segment: resolved_segment_idx as u32,
-                        reason,
-                    },
-                );
-            }
-        };
-
-        match resolution {
-            TypeNs::SelfType(_) => {
-                prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
-            }
-            TypeNs::GenericParam(_) => {
-                prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam)
-            }
-            TypeNs::AdtSelfType(_) => {
-                prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
-            }
-            TypeNs::BuiltinType(_) => {
-                prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy)
-            }
-            TypeNs::AdtId(_)
-            | TypeNs::EnumVariantId(_)
-            | TypeNs::TypeAliasId(_)
-            | TypeNs::TraitId(_)
-            | TypeNs::TraitAliasId(_) => {}
-        }
-    }
-
-    pub(crate) fn resolve_path_in_type_ns_fully(
-        &mut self,
-        path: &Path,
-        on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
-    ) -> Option<TypeNs> {
-        let (res, unresolved) = self.resolve_path_in_type_ns(path, on_diagnostic)?;
-        if unresolved.is_some() {
-            return None;
-        }
-        Some(res)
-    }
-
-    pub(crate) fn resolve_path_in_type_ns(
-        &mut self,
-        path: &Path,
-        on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
-    ) -> Option<(TypeNs, Option<usize>)> {
-        let (resolution, remaining_index, _, prefix_info) =
-            self.resolver.resolve_path_in_type_ns_with_prefix_info(self.db.upcast(), path)?;
-        let segments = path.segments();
-
-        match path {
-            // `segments.is_empty()` can occur with `self`.
-            Path::Normal(..) if !segments.is_empty() => (),
-            _ => return Some((resolution, remaining_index)),
-        };
-
-        let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index {
-            None if prefix_info.enum_variant => {
-                (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2))
-            }
-            None => (segments.strip_last(), segments.len() - 1, None),
-            Some(i) => (segments.take(i - 1), i - 1, None),
-        };
-
-        for (i, mod_segment) in module_segments.iter().enumerate() {
-            if mod_segment.args_and_bindings.is_some() {
-                on_diagnostic(
-                    self,
-                    PathLoweringDiagnostic::GenericArgsProhibited {
-                        segment: i as u32,
-                        reason: GenericArgsProhibitedReason::Module,
-                    },
-                );
-            }
-        }
-
-        if let Some(enum_segment) = enum_segment {
-            if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
-                && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
-            {
-                on_diagnostic(
-                    self,
-                    PathLoweringDiagnostic::GenericArgsProhibited {
-                        segment: (enum_segment + 1) as u32,
-                        reason: GenericArgsProhibitedReason::EnumVariant,
-                    },
-                );
-            }
-        }
-
-        self.handle_type_ns_resolution(
-            &resolution,
-            segments.get(resolved_segment_idx).expect("should have resolved segment"),
-            resolved_segment_idx,
-            on_diagnostic,
-        );
-
-        Some((resolution, remaining_index))
-    }
-
-    pub(crate) fn resolve_path_in_value_ns(
-        &mut self,
-        path: &Path,
-        hygiene_id: HygieneId,
-        on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
-    ) -> Option<ResolveValueResult> {
-        let (res, prefix_info) = self.resolver.resolve_path_in_value_ns_with_prefix_info(
-            self.db.upcast(),
-            path,
-            hygiene_id,
-        )?;
-
-        let segments = path.segments();
-        match path {
-            // `segments.is_empty()` can occur with `self`.
-            Path::Normal(..) if !segments.is_empty() => (),
-            _ => return Some(res),
-        };
-
-        let (mod_segments, enum_segment) = match res {
-            ResolveValueResult::Partial(_, unresolved_segment, _) => {
-                (segments.take(unresolved_segment - 1), None)
-            }
-            ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
-                if prefix_info.enum_variant =>
-            {
-                (segments.strip_last_two(), segments.len().checked_sub(2))
-            }
-            ResolveValueResult::ValueNs(..) => (segments.strip_last(), None),
-        };
-        for (i, mod_segment) in mod_segments.iter().enumerate() {
-            if mod_segment.args_and_bindings.is_some() {
-                on_diagnostic(
-                    self,
-                    PathLoweringDiagnostic::GenericArgsProhibited {
-                        segment: i as u32,
-                        reason: GenericArgsProhibitedReason::Module,
-                    },
-                );
-            }
-        }
-
-        if let Some(enum_segment) = enum_segment {
-            if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
-                && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
-            {
-                on_diagnostic(
-                    self,
-                    PathLoweringDiagnostic::GenericArgsProhibited {
-                        segment: (enum_segment + 1) as u32,
-                        reason: GenericArgsProhibitedReason::EnumVariant,
-                    },
-                );
-            }
+    #[inline]
+    fn on_path_diagnostic_callback(type_ref: TypeRefId) -> PathDiagnosticCallback<'static> {
+        PathDiagnosticCallback {
+            data: Either::Left(PathDiagnosticCallbackData(type_ref)),
+            callback: |data, this, diag| {
+                let type_ref = data.as_ref().left().unwrap().0;
+                this.push_diagnostic(type_ref, TyLoweringDiagnosticKind::PathDiagnostic(diag))
+            },
         }
-
-        match &res {
-            ResolveValueResult::ValueNs(resolution, _) => {
-                let resolved_segment_idx =
-                    segments.len().checked_sub(1).unwrap_or_else(|| panic!("{path:?}"));
-                let resolved_segment = segments.last().unwrap();
-
-                let mut prohibit_generics_on_resolved = |reason| {
-                    if resolved_segment.args_and_bindings.is_some() {
-                        on_diagnostic(
-                            self,
-                            PathLoweringDiagnostic::GenericArgsProhibited {
-                                segment: resolved_segment_idx as u32,
-                                reason,
-                            },
-                        );
-                    }
-                };
-
-                match resolution {
-                    ValueNs::ImplSelf(_) => {
-                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
-                    }
-                    // FIXME: rustc generates E0107 (incorrect number of generic arguments) and not
-                    // E0109 (generic arguments provided for a type that doesn't accept them) for
-                    // consts and statics, presumably as a defense against future in which consts
-                    // and statics can be generic, or just because it was easier for rustc implementors.
-                    // That means we'll show the wrong error code. Because of us it's easier to do it
-                    // this way :)
-                    ValueNs::GenericParam(_) | ValueNs::ConstId(_) => {
-                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const)
-                    }
-                    ValueNs::StaticId(_) => {
-                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static)
-                    }
-                    ValueNs::FunctionId(_) | ValueNs::StructId(_) | ValueNs::EnumVariantId(_) => {}
-                    ValueNs::LocalBinding(_) => {}
-                }
-            }
-            ResolveValueResult::Partial(resolution, unresolved_idx, _) => {
-                let resolved_segment_idx = unresolved_idx - 1;
-                let resolved_segment = segments.get(resolved_segment_idx).unwrap();
-                self.handle_type_ns_resolution(
-                    resolution,
-                    resolved_segment,
-                    resolved_segment_idx,
-                    on_diagnostic,
-                );
-            }
-        };
-        Some(res)
     }
 
-    fn on_path_diagnostic_callback(
-        type_ref: TypeRefId,
-    ) -> impl FnMut(&mut Self, PathLoweringDiagnostic) {
-        move |this, diag| {
-            this.push_diagnostic(type_ref, TyLoweringDiagnosticKind::PathDiagnostic(diag))
-        }
+    #[inline]
+    fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a> {
+        PathLoweringContext::new(
+            self,
+            Self::on_path_diagnostic_callback(path_id.type_ref()),
+            &self.types_map[path_id],
+        )
     }
 
     pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option<TypeNs>) {
         // Resolve the path (in type namespace)
         if let Some(type_ref) = path.type_anchor() {
             let (ty, res) = self.lower_ty_ext(type_ref);
-            return self.lower_ty_relative_path(ty, res, path.segments());
+            let mut ctx = self.at_path(path_id);
+            return ctx.lower_ty_relative_path(ty, res);
         }
 
-        let (resolution, remaining_index) = match self.resolve_path_in_type_ns(
-            path,
-            &mut Self::on_path_diagnostic_callback(path_id.type_ref()),
-        ) {
+        let mut ctx = self.at_path(path_id);
+        let (resolution, remaining_index) = match ctx.resolve_path_in_type_ns() {
             Some(it) => it,
             None => return (TyKind::Error.intern(Interner), None),
         };
@@ -953,354 +580,21 @@ impl<'a> TyLoweringContext<'a> {
             return (ty, None);
         }
 
-        let (resolved_segment_idx, resolved_segment, remaining_segments) = match remaining_index {
-            None => (
-                path.segments().len() - 1,
-                path.segments().last().expect("resolved path has at least one element"),
-                PathSegments::EMPTY,
-            ),
-            Some(i) => (i - 1, path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
-        };
-
-        self.lower_partly_resolved_path(
-            resolution,
-            resolved_segment,
-            remaining_segments,
-            resolved_segment_idx as u32,
-            false,
-            &mut Self::on_path_diagnostic_callback(path_id.type_ref()),
-        )
-    }
-
-    fn select_associated_type(&mut self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
-        let Some((generics, res)) = self.generics().zip(res) else {
-            return TyKind::Error.intern(Interner);
-        };
-        let ty = named_associated_type_shorthand_candidates(
-            self.db,
-            generics.def(),
-            res,
-            Some(segment.name.clone()),
-            move |name, t, associated_ty| {
-                let generics = self.generics().unwrap();
-
-                if name != segment.name {
-                    return None;
-                }
-
-                let parent_subst = t.substitution.clone();
-                let parent_subst = match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => {
-                        // if we're lowering to placeholders, we have to put them in now.
-                        let s = generics.placeholder_subst(self.db);
-                        s.apply(parent_subst, Interner)
-                    }
-                    ParamLoweringMode::Variable => {
-                        // We need to shift in the bound vars, since
-                        // `named_associated_type_shorthand_candidates` does not do that.
-                        parent_subst.shifted_in_from(Interner, self.in_binders)
-                    }
-                };
-
-                // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
-                // generic params. It's inefficient to splice the `Substitution`s, so we may want
-                // that method to optionally take parent `Substitution` as we already know them at
-                // this point (`t.substitution`).
-                let substs =
-                    self.substs_from_path_segment(segment, Some(associated_ty.into()), false, None);
-
-                let len_self =
-                    crate::generics::generics(self.db.upcast(), associated_ty.into()).len_self();
-
-                let substs = Substitution::from_iter(
-                    Interner,
-                    substs.iter(Interner).take(len_self).chain(parent_subst.iter(Interner)),
-                );
-
-                Some(
-                    TyKind::Alias(AliasTy::Projection(ProjectionTy {
-                        associated_ty_id: to_assoc_type_id(associated_ty),
-                        substitution: substs,
-                    }))
-                    .intern(Interner),
-                )
-            },
-        );
-
-        ty.unwrap_or_else(|| TyKind::Error.intern(Interner))
-    }
-
-    fn lower_path_inner(
-        &mut self,
-        segment: PathSegment<'_>,
-        typeable: TyDefId,
-        infer_args: bool,
-    ) -> Ty {
-        let generic_def = match typeable {
-            TyDefId::BuiltinType(_) => None,
-            TyDefId::AdtId(it) => Some(it.into()),
-            TyDefId::TypeAliasId(it) => Some(it.into()),
-        };
-        let substs = self.substs_from_path_segment(segment, generic_def, infer_args, None);
-        self.db.ty(typeable).substitute(Interner, &substs)
-    }
-
-    /// Collect generic arguments from a path into a `Substs`. See also
-    /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
-    pub(super) fn substs_from_path(
-        &mut self,
-        path: &Path,
-        // Note that we don't call `db.value_type(resolved)` here,
-        // `ValueTyDefId` is just a convenient way to pass generics and
-        // special-case enum variants
-        resolved: ValueTyDefId,
-        infer_args: bool,
-    ) -> Substitution {
-        let last = path.segments().last();
-        let (segment, generic_def) = match resolved {
-            ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
-            ValueTyDefId::StructId(it) => (last, Some(it.into())),
-            ValueTyDefId::UnionId(it) => (last, Some(it.into())),
-            ValueTyDefId::ConstId(it) => (last, Some(it.into())),
-            ValueTyDefId::StaticId(_) => (last, None),
-            ValueTyDefId::EnumVariantId(var) => {
-                // the generic args for an enum variant may be either specified
-                // on the segment referring to the enum, or on the segment
-                // referring to the variant. So `Option::<T>::None` and
-                // `Option::None::<T>` are both allowed (though the former is
-                // preferred). See also `def_ids_for_path_segments` in rustc.
-                let len = path.segments().len();
-                let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
-                let segment = match penultimate {
-                    Some(segment) if segment.args_and_bindings.is_some() => Some(segment),
-                    _ => last,
-                };
-                (segment, Some(var.lookup(self.db.upcast()).parent.into()))
-            }
-        };
-        if let Some(segment) = segment {
-            self.substs_from_path_segment(segment, generic_def, infer_args, None)
-        } else if let Some(generic_def) = generic_def {
-            // lang item
-            self.substs_from_args_and_bindings(None, Some(generic_def), infer_args, None)
-        } else {
-            Substitution::empty(Interner)
-        }
-    }
-
-    pub(super) fn substs_from_path_segment(
-        &mut self,
-        segment: PathSegment<'_>,
-        def: Option<GenericDefId>,
-        infer_args: bool,
-        explicit_self_ty: Option<Ty>,
-    ) -> Substitution {
-        self.substs_from_args_and_bindings(
-            segment.args_and_bindings,
-            def,
-            infer_args,
-            explicit_self_ty,
-        )
-    }
-
-    fn substs_from_args_and_bindings(
-        &mut self,
-        args_and_bindings: Option<&GenericArgs>,
-        def: Option<GenericDefId>,
-        infer_args: bool,
-        explicit_self_ty: Option<Ty>,
-    ) -> Substitution {
-        let Some(def) = def else { return Substitution::empty(Interner) };
-
-        // Order is
-        // - Optional Self parameter
-        // - Lifetime parameters
-        // - Type or Const parameters
-        // - Parent parameters
-        let def_generics = generics(self.db.upcast(), def);
-        let (
-            parent_params,
-            self_param,
-            type_params,
-            const_params,
-            impl_trait_params,
-            lifetime_params,
-        ) = def_generics.provenance_split();
-        let item_len =
-            self_param as usize + type_params + const_params + impl_trait_params + lifetime_params;
-        let total_len = parent_params + item_len;
-
-        let mut substs = Vec::new();
-
-        // we need to iterate the lifetime and type/const params separately as our order of them
-        // differs from the supplied syntax
-
-        let ty_error = || TyKind::Error.intern(Interner).cast(Interner);
-        let mut def_toc_iter = def_generics.iter_self_type_or_consts_id();
-        let fill_self_param = || {
-            if self_param {
-                let self_ty = explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(ty_error);
-
-                if let Some(id) = def_toc_iter.next() {
-                    assert!(matches!(id, GenericParamId::TypeParamId(_)));
-                    substs.push(self_ty);
-                }
-            }
-        };
-        let mut had_explicit_args = false;
-
-        if let Some(&GenericArgs { ref args, has_self_type, .. }) = args_and_bindings {
-            // Fill in the self param first
-            if has_self_type && self_param {
-                had_explicit_args = true;
-                if let Some(id) = def_toc_iter.next() {
-                    assert!(matches!(id, GenericParamId::TypeParamId(_)));
-                    had_explicit_args = true;
-                    if let GenericArg::Type(ty) = &args[0] {
-                        substs.push(self.lower_ty(*ty).cast(Interner));
-                    }
-                }
-            } else {
-                fill_self_param()
-            };
-
-            // Then fill in the supplied lifetime args, or error lifetimes if there are too few
-            // (default lifetimes aren't a thing)
-            for arg in args
-                .iter()
-                .filter_map(|arg| match arg {
-                    GenericArg::Lifetime(arg) => Some(self.lower_lifetime(arg)),
-                    _ => None,
-                })
-                .chain(iter::repeat(error_lifetime()))
-                .take(lifetime_params)
-            {
-                substs.push(arg.cast(Interner));
-            }
-
-            let skip = if has_self_type { 1 } else { 0 };
-            // Fill in supplied type and const args
-            // Note if non-lifetime args are provided, it should be all of them, but we can't rely on that
-            for (arg, id) in args
-                .iter()
-                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
-                .skip(skip)
-                .take(type_params + const_params)
-                .zip(def_toc_iter)
-            {
-                had_explicit_args = true;
-                let arg = generic_arg_to_chalk(
-                    self.db,
-                    id,
-                    arg,
-                    self,
-                    self.types_map,
-                    |this, type_ref| this.lower_ty(type_ref),
-                    |this, const_ref, ty| this.lower_const(const_ref, ty),
-                    |this, lifetime_ref| this.lower_lifetime(lifetime_ref),
-                );
-                substs.push(arg);
-            }
-        } else {
-            fill_self_param();
-        }
-
-        let param_to_err = |id| match id {
-            GenericParamId::ConstParamId(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
-            GenericParamId::TypeParamId(_) => ty_error(),
-            GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
-        };
-        // handle defaults. In expression or pattern path segments without
-        // explicitly specified type arguments, missing type arguments are inferred
-        // (i.e. defaults aren't used).
-        // Generic parameters for associated types are not supposed to have defaults, so we just
-        // ignore them.
-        let is_assoc_ty = || match def {
-            GenericDefId::TypeAliasId(id) => {
-                matches!(id.lookup(self.db.upcast()).container, ItemContainerId::TraitId(_))
-            }
-            _ => false,
-        };
-        let fill_defaults = (!infer_args || had_explicit_args) && !is_assoc_ty();
-        if fill_defaults {
-            let defaults = &*self.db.generic_defaults(def);
-            let (item, _parent) = defaults.split_at(item_len);
-            let parent_from = item_len - substs.len();
-
-            let mut rem =
-                def_generics.iter_id().skip(substs.len()).map(param_to_err).collect::<Vec<_>>();
-            // Fill in defaults for type/const params
-            for (idx, default_ty) in item[substs.len()..].iter().enumerate() {
-                // each default can depend on the previous parameters
-                let substs_so_far = Substitution::from_iter(
-                    Interner,
-                    substs.iter().cloned().chain(rem[idx..].iter().cloned()),
-                );
-                substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
-            }
-            // Fill in remaining parent params
-            substs.extend(rem.drain(parent_from..));
-        } else {
-            // Fill in remaining def params and parent params
-            substs.extend(def_generics.iter_id().skip(substs.len()).map(param_to_err));
-        }
-
-        assert_eq!(substs.len(), total_len, "expected {} substs, got {}", total_len, substs.len());
-        Substitution::from_iter(Interner, substs)
-    }
-
-    pub(crate) fn lower_trait_ref_from_resolved_path(
-        &mut self,
-        resolved: TraitId,
-        segment: PathSegment<'_>,
-        explicit_self_ty: Ty,
-    ) -> TraitRef {
-        let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty);
-        TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
-    }
-
-    fn prohibit_generics(
-        &mut self,
-        path_id: PathId,
-        idx: u32,
-        segments: PathSegments<'_>,
-        reason: GenericArgsProhibitedReason,
-    ) {
-        segments.iter().zip(idx..).for_each(|(segment, idx)| {
-            if segment.args_and_bindings.is_some() {
-                self.push_diagnostic(
-                    path_id.type_ref(),
-                    TyLoweringDiagnosticKind::PathDiagnostic(
-                        PathLoweringDiagnostic::GenericArgsProhibited { segment: idx, reason },
-                    ),
-                );
-            }
-        });
+        ctx.lower_partly_resolved_path(resolution, false)
     }
 
     fn lower_trait_ref_from_path(
         &mut self,
         path_id: PathId,
         explicit_self_ty: Ty,
-    ) -> Option<TraitRef> {
-        let path = &self.types_map[path_id];
-        let resolved = match self.resolve_path_in_type_ns_fully(
-            path,
-            &mut Self::on_path_diagnostic_callback(path_id.type_ref()),
-        )? {
+    ) -> Option<(TraitRef, PathLoweringContext<'_, 'a>)> {
+        let mut ctx = self.at_path(path_id);
+        let resolved = match ctx.resolve_path_in_type_ns_fully()? {
             // FIXME(trait_alias): We need to handle trait alias here.
             TypeNs::TraitId(tr) => tr,
             _ => return None,
         };
-        // Do this after we verify it's indeed a trait to not confuse the user if they're not modules.
-        self.prohibit_generics(
-            path_id,
-            0,
-            path.segments().strip_last(),
-            GenericArgsProhibitedReason::Module,
-        );
-        let segment = path.segments().last().expect("path should have at least one segment");
-        Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty))
+        Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty), ctx))
     }
 
     fn lower_trait_ref(
@@ -1308,16 +602,7 @@ impl<'a> TyLoweringContext<'a> {
         trait_ref: &HirTraitRef,
         explicit_self_ty: Ty,
     ) -> Option<TraitRef> {
-        self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty)
-    }
-
-    fn trait_ref_substs_from_path(
-        &mut self,
-        segment: PathSegment<'_>,
-        resolved: TraitId,
-        explicit_self_ty: Ty,
-    ) -> Substitution {
-        self.substs_from_path_segment(segment, Some(resolved.into()), false, Some(explicit_self_ty))
+        self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0)
     }
 
     pub(crate) fn lower_where_predicate<'b>(
@@ -1365,11 +650,18 @@ impl<'a> TyLoweringContext<'a> {
         self_ty: Ty,
         ignore_bindings: bool,
     ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'b, 'a> {
-        let mut trait_ref = None;
-        let clause = match bound {
-            &TypeBound::Path(path, TraitBoundModifier::None) => {
-                trait_ref = self.lower_trait_ref_from_path(path, self_ty);
-                trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
+        let mut assoc_bounds = None;
+        let mut clause = None;
+        match bound {
+            &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => {
+                // FIXME Don't silently drop the hrtb lifetimes here
+                if let Some((trait_ref, ctx)) = self.lower_trait_ref_from_path(path, self_ty) {
+                    if !ignore_bindings {
+                        assoc_bounds =
+                            ctx.assoc_type_bindings_from_type_bound(bound, trait_ref.clone());
+                    }
+                    clause = Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref)));
+                }
             }
             &TypeBound::Path(path, TraitBoundModifier::Maybe) => {
                 let sized_trait = self
@@ -1381,170 +673,21 @@ impl<'a> TyLoweringContext<'a> {
                 // If we got another trait here ignore the bound completely.
                 let trait_id = self
                     .lower_trait_ref_from_path(path, self_ty.clone())
-                    .map(|trait_ref| trait_ref.hir_trait_id());
+                    .map(|(trait_ref, _)| trait_ref.hir_trait_id());
                 if trait_id == sized_trait {
                     self.unsized_types.insert(self_ty);
                 }
-                None
-            }
-            &TypeBound::ForLifetime(_, path) => {
-                // FIXME Don't silently drop the hrtb lifetimes here
-                trait_ref = self.lower_trait_ref_from_path(path, self_ty);
-                trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
             }
             TypeBound::Lifetime(l) => {
                 let lifetime = self.lower_lifetime(l);
-                Some(crate::wrap_empty_binders(WhereClause::TypeOutlives(TypeOutlives {
+                clause = Some(crate::wrap_empty_binders(WhereClause::TypeOutlives(TypeOutlives {
                     ty: self_ty,
                     lifetime,
-                })))
+                })));
             }
-            TypeBound::Use(_) | TypeBound::Error => None,
-        };
-        clause.into_iter().chain(
-            trait_ref
-                .filter(move |_| !ignore_bindings)
-                .map(move |tr| self.assoc_type_bindings_from_type_bound(bound, tr))
-                .into_iter()
-                .flatten(),
-        )
-    }
-
-    fn assoc_type_bindings_from_type_bound<'b>(
-        &'b mut self,
-        bound: &'b TypeBound,
-        trait_ref: TraitRef,
-    ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'b, 'a> {
-        let last_segment = match bound {
-            &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => {
-                self.types_map[path].segments().last()
-            }
-            TypeBound::Path(_, TraitBoundModifier::Maybe)
-            | TypeBound::Use(_)
-            | TypeBound::Error
-            | TypeBound::Lifetime(_) => None,
-        };
-        last_segment
-            .into_iter()
-            .filter_map(|segment| segment.args_and_bindings)
-            .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
-            .flat_map(move |binding| {
-                let found = associated_type_by_name_including_super_traits(
-                    self.db,
-                    trait_ref.clone(),
-                    &binding.name,
-                );
-                let (super_trait_ref, associated_ty) = match found {
-                    None => return SmallVec::new(),
-                    Some(t) => t,
-                };
-                // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
-                // generic params. It's inefficient to splice the `Substitution`s, so we may want
-                // that method to optionally take parent `Substitution` as we already know them at
-                // this point (`super_trait_ref.substitution`).
-                let substitution = self.substs_from_path_segment(
-                    // FIXME: This is hack. We shouldn't really build `PathSegment` directly.
-                    PathSegment { name: &binding.name, args_and_bindings: binding.args.as_ref() },
-                    Some(associated_ty.into()),
-                    false, // this is not relevant
-                    Some(super_trait_ref.self_type_parameter(Interner)),
-                );
-                let self_params = generics(self.db.upcast(), associated_ty.into()).len_self();
-                let substitution = Substitution::from_iter(
-                    Interner,
-                    substitution
-                        .iter(Interner)
-                        .take(self_params)
-                        .chain(super_trait_ref.substitution.iter(Interner)),
-                );
-                let projection_ty = ProjectionTy {
-                    associated_ty_id: to_assoc_type_id(associated_ty),
-                    substitution,
-                };
-                let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
-                    binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
-                );
-                if let Some(type_ref) = binding.type_ref {
-                    match (&self.types_map[type_ref], self.impl_trait_mode.mode) {
-                        (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
-                        (_, ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque) => {
-                            let ty = self.lower_ty(type_ref);
-                            let alias_eq =
-                                AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
-                            predicates
-                                .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
-                        }
-                        (_, ImplTraitLoweringMode::Param | ImplTraitLoweringMode::Variable) => {
-                            // Find the generic index for the target of our `bound`
-                            let target_param_idx = self
-                                .resolver
-                                .where_predicates_in_scope()
-                                .find_map(|(p, _)| match p {
-                                    WherePredicate::TypeBound {
-                                        target: WherePredicateTypeTarget::TypeOrConstParam(idx),
-                                        bound: b,
-                                    } if b == bound => Some(idx),
-                                    _ => None,
-                                });
-                            let ty = if let Some(target_param_idx) = target_param_idx {
-                                let mut counter = 0;
-                                let generics = self.generics().expect("generics in scope");
-                                for (idx, data) in generics.iter_self_type_or_consts() {
-                                    // Count the number of `impl Trait` things that appear before
-                                    // the target of our `bound`.
-                                    // Our counter within `impl_trait_mode` should be that number
-                                    // to properly lower each types within `type_ref`
-                                    if data.type_param().is_some_and(|p| {
-                                        p.provenance == TypeParamProvenance::ArgumentImplTrait
-                                    }) {
-                                        counter += 1;
-                                    }
-                                    if idx == *target_param_idx {
-                                        break;
-                                    }
-                                }
-                                let mut ext = TyLoweringContext::new_maybe_unowned(
-                                    self.db,
-                                    self.resolver,
-                                    self.types_map,
-                                    self.types_source_map,
-                                    self.owner,
-                                )
-                                .with_type_param_mode(self.type_param_mode);
-                                match self.impl_trait_mode.mode {
-                                    ImplTraitLoweringMode::Param => {
-                                        ext.impl_trait_mode =
-                                            ImplTraitLoweringState::param(counter);
-                                    }
-                                    ImplTraitLoweringMode::Variable => {
-                                        ext.impl_trait_mode =
-                                            ImplTraitLoweringState::variable(counter);
-                                    }
-                                    _ => unreachable!(),
-                                }
-                                let ty = ext.lower_ty(type_ref);
-                                self.diagnostics.extend(ext.diagnostics);
-                                ty
-                            } else {
-                                self.lower_ty(type_ref)
-                            };
-
-                            let alias_eq =
-                                AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
-                            predicates
-                                .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
-                        }
-                    }
-                }
-                for bound in binding.bounds.iter() {
-                    predicates.extend(self.lower_type_bound(
-                        bound,
-                        TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner),
-                        false,
-                    ));
-                }
-                predicates
-            })
+            TypeBound::Use(_) | TypeBound::Error => {}
+        }
+        clause.into_iter().chain(assoc_bounds.into_iter().flatten())
     }
 
     fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/diagnostics.rs
index 7fe196cdbb5..5c77bcd0736 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/diagnostics.rs
@@ -26,11 +26,11 @@ pub enum GenericArgsProhibitedReason {
     Static,
     /// When there is a generic enum, within the expression `Enum::Variant`,
     /// either `Enum` or `Variant` are allowed to have generic arguments, but not both.
-    // FIXME: This is not used now but it should be.
     EnumVariant,
 }
 
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum PathLoweringDiagnostic {
     GenericArgsProhibited { segment: u32, reason: GenericArgsProhibitedReason },
+    ParenthesizedGenericArgsWithoutFnTrait { segment: u32 },
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
new file mode 100644
index 00000000000..22c5bb9923f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
@@ -0,0 +1,911 @@
+//! A wrapper around [`TyLoweringContext`] specifically for lowering paths.
+
+use std::iter;
+
+use chalk_ir::{cast::Cast, fold::Shift, BoundVar};
+use either::Either;
+use hir_def::{
+    data::TraitFlags,
+    expr_store::HygieneId,
+    generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
+    path::{GenericArg, GenericArgs, Path, PathSegment, PathSegments},
+    resolver::{ResolveValueResult, TypeNs, ValueNs},
+    type_ref::{TypeBound, TypeRef},
+    GenericDefId, GenericParamId, ItemContainerId, Lookup, TraitId,
+};
+use smallvec::SmallVec;
+use stdx::never;
+
+use crate::{
+    consteval::unknown_const_as_generic,
+    error_lifetime,
+    generics::generics,
+    lower::{
+        generic_arg_to_chalk, named_associated_type_shorthand_candidates, ImplTraitLoweringState,
+    },
+    to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
+    utils::associated_type_by_name_including_super_traits,
+    AliasEq, AliasTy, GenericArgsProhibitedReason, ImplTraitLoweringMode, Interner,
+    ParamLoweringMode, PathLoweringDiagnostic, ProjectionTy, QuantifiedWhereClause, Substitution,
+    TraitRef, Ty, TyBuilder, TyDefId, TyKind, TyLoweringContext, ValueTyDefId, WhereClause,
+};
+
+type CallbackData<'a> = Either<
+    super::PathDiagnosticCallbackData,
+    crate::infer::diagnostics::PathDiagnosticCallbackData<'a>,
+>;
+
+// We cannot use `&mut dyn FnMut()` because of lifetime issues, and we don't want to use `Box<dyn FnMut()>`
+// because of the allocation, so we create a lifetime-less callback, tailored for our needs.
+pub(crate) struct PathDiagnosticCallback<'a> {
+    pub(crate) data: CallbackData<'a>,
+    pub(crate) callback: fn(&CallbackData<'_>, &mut TyLoweringContext<'_>, PathLoweringDiagnostic),
+}
+
+pub(crate) struct PathLoweringContext<'a, 'b> {
+    ctx: &'a mut TyLoweringContext<'b>,
+    on_diagnostic: PathDiagnosticCallback<'a>,
+    path: &'a Path,
+    segments: PathSegments<'a>,
+    current_segment_idx: usize,
+    /// Contains the previous segment if `current_segment_idx == segments.len()`
+    current_or_prev_segment: PathSegment<'a>,
+}
+
+impl<'a, 'b> PathLoweringContext<'a, 'b> {
+    #[inline]
+    pub(crate) fn new(
+        ctx: &'a mut TyLoweringContext<'b>,
+        on_diagnostic: PathDiagnosticCallback<'a>,
+        path: &'a Path,
+    ) -> Self {
+        let segments = path.segments();
+        let first_segment = segments.first().unwrap_or(PathSegment::MISSING);
+        Self {
+            ctx,
+            on_diagnostic,
+            path,
+            segments,
+            current_segment_idx: 0,
+            current_or_prev_segment: first_segment,
+        }
+    }
+
+    #[inline]
+    #[cold]
+    fn on_diagnostic(&mut self, diag: PathLoweringDiagnostic) {
+        (self.on_diagnostic.callback)(&self.on_diagnostic.data, self.ctx, diag);
+    }
+
+    #[inline]
+    pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'b> {
+        self.ctx
+    }
+
+    #[inline]
+    fn current_segment_u32(&self) -> u32 {
+        self.current_segment_idx as u32
+    }
+
+    #[inline]
+    fn skip_resolved_segment(&mut self) {
+        if !matches!(self.path, Path::LangItem(..)) {
+            // In lang items, the resolved "segment" is not one of the segments. Perhaps we should've put it
+            // point at -1, but I don't feel this is clearer.
+            self.current_segment_idx += 1;
+        }
+        self.update_current_segment();
+    }
+
+    #[inline]
+    fn update_current_segment(&mut self) {
+        self.current_or_prev_segment =
+            self.segments.get(self.current_segment_idx).unwrap_or(self.current_or_prev_segment);
+    }
+
+    #[inline]
+    pub(crate) fn ignore_last_segment(&mut self) {
+        self.segments = self.segments.strip_last();
+    }
+
+    #[inline]
+    pub(crate) fn set_current_segment(&mut self, segment: usize) {
+        self.current_segment_idx = segment;
+        self.current_or_prev_segment = self
+            .segments
+            .get(segment)
+            .expect("invalid segment passed to PathLoweringContext::set_current_segment()");
+    }
+
+    pub(crate) fn lower_ty_relative_path(
+        &mut self,
+        ty: Ty,
+        // We need the original resolution to lower `Self::AssocTy` correctly
+        res: Option<TypeNs>,
+    ) -> (Ty, Option<TypeNs>) {
+        match self.segments.len() - self.current_segment_idx {
+            0 => (ty, res),
+            1 => {
+                // resolve unselected assoc types
+                (self.select_associated_type(res), None)
+            }
+            _ => {
+                // FIXME report error (ambiguous associated type)
+                (TyKind::Error.intern(Interner), None)
+            }
+        }
+    }
+
+    fn prohibit_parenthesized_generic_args(&mut self) -> bool {
+        if let Some(generic_args) = self.current_or_prev_segment.args_and_bindings {
+            if generic_args.desugared_from_fn {
+                let segment = self.current_segment_u32();
+                self.on_diagnostic(
+                    PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
+                );
+                return true;
+            }
+        }
+        false
+    }
+
+    // When calling this, the current segment is the resolved segment (we don't advance it yet).
+    pub(crate) fn lower_partly_resolved_path(
+        &mut self,
+        resolution: TypeNs,
+        infer_args: bool,
+    ) -> (Ty, Option<TypeNs>) {
+        let remaining_segments = self.segments.skip(self.current_segment_idx + 1);
+
+        let ty = match resolution {
+            TypeNs::TraitId(trait_) => {
+                let ty = match remaining_segments.len() {
+                    1 => {
+                        let trait_ref = self.lower_trait_ref_from_resolved_path(
+                            trait_,
+                            TyKind::Error.intern(Interner),
+                        );
+
+                        self.skip_resolved_segment();
+                        let segment = self.current_or_prev_segment;
+                        let found =
+                            self.ctx.db.trait_data(trait_).associated_type_by_name(segment.name);
+
+                        match found {
+                            Some(associated_ty) => {
+                                // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+                                // generic params. It's inefficient to splice the `Substitution`s, so we may want
+                                // that method to optionally take parent `Substitution` as we already know them at
+                                // this point (`trait_ref.substitution`).
+                                let substitution = self.substs_from_path_segment(
+                                    associated_ty.into(),
+                                    false,
+                                    None,
+                                );
+                                let len_self =
+                                    generics(self.ctx.db.upcast(), associated_ty.into()).len_self();
+                                let substitution = Substitution::from_iter(
+                                    Interner,
+                                    substitution
+                                        .iter(Interner)
+                                        .take(len_self)
+                                        .chain(trait_ref.substitution.iter(Interner)),
+                                );
+                                TyKind::Alias(AliasTy::Projection(ProjectionTy {
+                                    associated_ty_id: to_assoc_type_id(associated_ty),
+                                    substitution,
+                                }))
+                                .intern(Interner)
+                            }
+                            None => {
+                                // FIXME: report error (associated type not found)
+                                TyKind::Error.intern(Interner)
+                            }
+                        }
+                    }
+                    0 => {
+                        // Trait object type without dyn; this should be handled in upstream. See
+                        // `lower_path()`.
+                        stdx::never!("unexpected fully resolved trait path");
+                        TyKind::Error.intern(Interner)
+                    }
+                    _ => {
+                        // FIXME report error (ambiguous associated type)
+                        TyKind::Error.intern(Interner)
+                    }
+                };
+                return (ty, None);
+            }
+            TypeNs::TraitAliasId(_) => {
+                // FIXME(trait_alias): Implement trait alias.
+                return (TyKind::Error.intern(Interner), None);
+            }
+            TypeNs::GenericParam(param_id) => match self.ctx.type_param_mode {
+                ParamLoweringMode::Placeholder => {
+                    TyKind::Placeholder(to_placeholder_idx(self.ctx.db, param_id.into()))
+                }
+                ParamLoweringMode::Variable => {
+                    let idx = match self
+                        .ctx
+                        .generics()
+                        .expect("generics in scope")
+                        .type_or_const_param_idx(param_id.into())
+                    {
+                        None => {
+                            never!("no matching generics");
+                            return (TyKind::Error.intern(Interner), None);
+                        }
+                        Some(idx) => idx,
+                    };
+
+                    TyKind::BoundVar(BoundVar::new(self.ctx.in_binders, idx))
+                }
+            }
+            .intern(Interner),
+            TypeNs::SelfType(impl_id) => {
+                let generics = self.ctx.generics().expect("impl should have generic param scope");
+
+                match self.ctx.type_param_mode {
+                    ParamLoweringMode::Placeholder => {
+                        // `def` can be either impl itself or item within, and we need impl itself
+                        // now.
+                        let generics = generics.parent_or_self();
+                        let subst = generics.placeholder_subst(self.ctx.db);
+                        self.ctx.db.impl_self_ty(impl_id).substitute(Interner, &subst)
+                    }
+                    ParamLoweringMode::Variable => {
+                        let starting_from = match generics.def() {
+                            GenericDefId::ImplId(_) => 0,
+                            // `def` is an item within impl. We need to substitute `BoundVar`s but
+                            // remember that they are for parent (i.e. impl) generic params so they
+                            // come after our own params.
+                            _ => generics.len_self(),
+                        };
+                        TyBuilder::impl_self_ty(self.ctx.db, impl_id)
+                            .fill_with_bound_vars(self.ctx.in_binders, starting_from)
+                            .build()
+                    }
+                }
+            }
+            TypeNs::AdtSelfType(adt) => {
+                let generics = generics(self.ctx.db.upcast(), adt.into());
+                let substs = match self.ctx.type_param_mode {
+                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.ctx.db),
+                    ParamLoweringMode::Variable => {
+                        generics.bound_vars_subst(self.ctx.db, self.ctx.in_binders)
+                    }
+                };
+                self.ctx.db.ty(adt.into()).substitute(Interner, &substs)
+            }
+
+            TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args),
+            TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args),
+            TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args),
+            // FIXME: report error
+            TypeNs::EnumVariantId(_) => return (TyKind::Error.intern(Interner), None),
+        };
+
+        self.skip_resolved_segment();
+        self.lower_ty_relative_path(ty, Some(resolution))
+    }
+
+    fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) {
+        let mut prohibit_generics_on_resolved = |reason| {
+            if self.current_or_prev_segment.args_and_bindings.is_some() {
+                let segment = self.current_segment_u32();
+                self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+                    segment,
+                    reason,
+                });
+            }
+        };
+
+        match resolution {
+            TypeNs::SelfType(_) => {
+                prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
+            }
+            TypeNs::GenericParam(_) => {
+                prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam)
+            }
+            TypeNs::AdtSelfType(_) => {
+                prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
+            }
+            TypeNs::BuiltinType(_) => {
+                prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy)
+            }
+            TypeNs::AdtId(_)
+            | TypeNs::EnumVariantId(_)
+            | TypeNs::TypeAliasId(_)
+            | TypeNs::TraitId(_)
+            | TypeNs::TraitAliasId(_) => {}
+        }
+    }
+
+    pub(crate) fn resolve_path_in_type_ns_fully(&mut self) -> Option<TypeNs> {
+        let (res, unresolved) = self.resolve_path_in_type_ns()?;
+        if unresolved.is_some() {
+            return None;
+        }
+        Some(res)
+    }
+
+    pub(crate) fn resolve_path_in_type_ns(&mut self) -> Option<(TypeNs, Option<usize>)> {
+        let (resolution, remaining_index, _, prefix_info) = self
+            .ctx
+            .resolver
+            .resolve_path_in_type_ns_with_prefix_info(self.ctx.db.upcast(), self.path)?;
+
+        let segments = self.segments;
+        if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
+            // `segments.is_empty()` can occur with `self`.
+            return Some((resolution, remaining_index));
+        }
+
+        let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index {
+            None if prefix_info.enum_variant => {
+                (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2))
+            }
+            None => (segments.strip_last(), segments.len() - 1, None),
+            Some(i) => (segments.take(i - 1), i - 1, None),
+        };
+
+        self.current_segment_idx = resolved_segment_idx;
+        self.current_or_prev_segment =
+            segments.get(resolved_segment_idx).expect("should have resolved segment");
+
+        if matches!(self.path, Path::BarePath(..)) {
+            // Bare paths cannot have generics, so skip them as an optimization.
+            return Some((resolution, remaining_index));
+        }
+
+        for (i, mod_segment) in module_segments.iter().enumerate() {
+            if mod_segment.args_and_bindings.is_some() {
+                self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+                    segment: i as u32,
+                    reason: GenericArgsProhibitedReason::Module,
+                });
+            }
+        }
+
+        if let Some(enum_segment) = enum_segment {
+            if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
+                && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
+            {
+                self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+                    segment: (enum_segment + 1) as u32,
+                    reason: GenericArgsProhibitedReason::EnumVariant,
+                });
+            }
+        }
+
+        self.handle_type_ns_resolution(&resolution);
+
+        Some((resolution, remaining_index))
+    }
+
+    pub(crate) fn resolve_path_in_value_ns(
+        &mut self,
+        hygiene_id: HygieneId,
+    ) -> Option<ResolveValueResult> {
+        let (res, prefix_info) = self.ctx.resolver.resolve_path_in_value_ns_with_prefix_info(
+            self.ctx.db.upcast(),
+            self.path,
+            hygiene_id,
+        )?;
+
+        let segments = self.segments;
+        if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
+            // `segments.is_empty()` can occur with `self`.
+            return Some(res);
+        }
+
+        let (mod_segments, enum_segment, resolved_segment_idx) = match res {
+            ResolveValueResult::Partial(_, unresolved_segment, _) => {
+                (segments.take(unresolved_segment - 1), None, unresolved_segment - 1)
+            }
+            ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
+                if prefix_info.enum_variant =>
+            {
+                (segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1)
+            }
+            ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1),
+        };
+
+        self.current_segment_idx = resolved_segment_idx;
+        self.current_or_prev_segment =
+            segments.get(resolved_segment_idx).expect("should have resolved segment");
+
+        for (i, mod_segment) in mod_segments.iter().enumerate() {
+            if mod_segment.args_and_bindings.is_some() {
+                self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+                    segment: i as u32,
+                    reason: GenericArgsProhibitedReason::Module,
+                });
+            }
+        }
+
+        if let Some(enum_segment) = enum_segment {
+            if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
+                && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
+            {
+                self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+                    segment: (enum_segment + 1) as u32,
+                    reason: GenericArgsProhibitedReason::EnumVariant,
+                });
+            }
+        }
+
+        match &res {
+            ResolveValueResult::ValueNs(resolution, _) => {
+                let resolved_segment_idx = self.current_segment_u32();
+                let resolved_segment = self.current_or_prev_segment;
+
+                let mut prohibit_generics_on_resolved = |reason| {
+                    if resolved_segment.args_and_bindings.is_some() {
+                        self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+                            segment: resolved_segment_idx,
+                            reason,
+                        });
+                    }
+                };
+
+                match resolution {
+                    ValueNs::ImplSelf(_) => {
+                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
+                    }
+                    // FIXME: rustc generates E0107 (incorrect number of generic arguments) and not
+                    // E0109 (generic arguments provided for a type that doesn't accept them) for
+                    // consts and statics, presumably as a defense against future in which consts
+                    // and statics can be generic, or just because it was easier for rustc implementors.
+                    // That means we'll show the wrong error code. Because of us it's easier to do it
+                    // this way :)
+                    ValueNs::GenericParam(_) | ValueNs::ConstId(_) => {
+                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const)
+                    }
+                    ValueNs::StaticId(_) => {
+                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static)
+                    }
+                    ValueNs::FunctionId(_) | ValueNs::StructId(_) | ValueNs::EnumVariantId(_) => {}
+                    ValueNs::LocalBinding(_) => {}
+                }
+            }
+            ResolveValueResult::Partial(resolution, _, _) => {
+                self.handle_type_ns_resolution(resolution);
+            }
+        };
+        Some(res)
+    }
+
+    fn select_associated_type(&mut self, res: Option<TypeNs>) -> Ty {
+        let Some((generics, res)) = self.ctx.generics().zip(res) else {
+            return TyKind::Error.intern(Interner);
+        };
+        let segment = self.current_or_prev_segment;
+        let ty = named_associated_type_shorthand_candidates(
+            self.ctx.db,
+            generics.def(),
+            res,
+            Some(segment.name.clone()),
+            move |name, t, associated_ty| {
+                let generics = self.ctx.generics().unwrap();
+
+                if name != segment.name {
+                    return None;
+                }
+
+                let parent_subst = t.substitution.clone();
+                let parent_subst = match self.ctx.type_param_mode {
+                    ParamLoweringMode::Placeholder => {
+                        // if we're lowering to placeholders, we have to put them in now.
+                        let s = generics.placeholder_subst(self.ctx.db);
+                        s.apply(parent_subst, Interner)
+                    }
+                    ParamLoweringMode::Variable => {
+                        // We need to shift in the bound vars, since
+                        // `named_associated_type_shorthand_candidates` does not do that.
+                        parent_subst.shifted_in_from(Interner, self.ctx.in_binders)
+                    }
+                };
+
+                // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+                // generic params. It's inefficient to splice the `Substitution`s, so we may want
+                // that method to optionally take parent `Substitution` as we already know them at
+                // this point (`t.substitution`).
+                let substs = self.substs_from_path_segment(associated_ty.into(), false, None);
+
+                let len_self =
+                    crate::generics::generics(self.ctx.db.upcast(), associated_ty.into())
+                        .len_self();
+
+                let substs = Substitution::from_iter(
+                    Interner,
+                    substs.iter(Interner).take(len_self).chain(parent_subst.iter(Interner)),
+                );
+
+                Some(
+                    TyKind::Alias(AliasTy::Projection(ProjectionTy {
+                        associated_ty_id: to_assoc_type_id(associated_ty),
+                        substitution: substs,
+                    }))
+                    .intern(Interner),
+                )
+            },
+        );
+
+        ty.unwrap_or_else(|| TyKind::Error.intern(Interner))
+    }
+
+    fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty {
+        let generic_def = match typeable {
+            TyDefId::BuiltinType(builtin) => return TyBuilder::builtin(builtin),
+            TyDefId::AdtId(it) => it.into(),
+            TyDefId::TypeAliasId(it) => it.into(),
+        };
+        let substs = self.substs_from_path_segment(generic_def, infer_args, None);
+        self.ctx.db.ty(typeable).substitute(Interner, &substs)
+    }
+
+    /// Collect generic arguments from a path into a `Substs`. See also
+    /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
+    pub(crate) fn substs_from_path(
+        &mut self,
+        // Note that we don't call `db.value_type(resolved)` here,
+        // `ValueTyDefId` is just a convenient way to pass generics and
+        // special-case enum variants
+        resolved: ValueTyDefId,
+        infer_args: bool,
+    ) -> Substitution {
+        let prev_current_segment_idx = self.current_segment_idx;
+        let prev_current_segment = self.current_or_prev_segment;
+
+        let generic_def = match resolved {
+            ValueTyDefId::FunctionId(it) => it.into(),
+            ValueTyDefId::StructId(it) => it.into(),
+            ValueTyDefId::UnionId(it) => it.into(),
+            ValueTyDefId::ConstId(it) => it.into(),
+            ValueTyDefId::StaticId(_) => return Substitution::empty(Interner),
+            ValueTyDefId::EnumVariantId(var) => {
+                // the generic args for an enum variant may be either specified
+                // on the segment referring to the enum, or on the segment
+                // referring to the variant. So `Option::<T>::None` and
+                // `Option::None::<T>` are both allowed (though the former is
+                // FIXME: This isn't strictly correct, enum variants may be used not through the enum
+                // (via `use Enum::Variant`). The resolver returns whether they were, but we don't have its result
+                // available here. The worst that can happen is that we will show some confusing diagnostics to the user,
+                // if generics exist on the module and they don't match with the variant.
+                // preferred). See also `def_ids_for_path_segments` in rustc.
+                //
+                // `wrapping_sub(1)` will return a number which `get` will return None for if current_segment_idx<2.
+                // This simplifies the code a bit.
+                let penultimate_idx = self.current_segment_idx.wrapping_sub(1);
+                let penultimate = self.segments.get(penultimate_idx);
+                if let Some(penultimate) = penultimate {
+                    if self.current_or_prev_segment.args_and_bindings.is_none()
+                        && penultimate.args_and_bindings.is_some()
+                    {
+                        self.current_segment_idx = penultimate_idx;
+                        self.current_or_prev_segment = penultimate;
+                    }
+                }
+                var.lookup(self.ctx.db.upcast()).parent.into()
+            }
+        };
+        let result = self.substs_from_path_segment(generic_def, infer_args, None);
+        self.current_segment_idx = prev_current_segment_idx;
+        self.current_or_prev_segment = prev_current_segment;
+        result
+    }
+
+    pub(crate) fn substs_from_path_segment(
+        &mut self,
+        def: GenericDefId,
+        infer_args: bool,
+        explicit_self_ty: Option<Ty>,
+    ) -> Substitution {
+        let prohibit_parens = match def {
+            GenericDefId::TraitId(trait_) => {
+                let trait_data = self.ctx.db.trait_data(trait_);
+                !trait_data.flags.contains(TraitFlags::RUSTC_PAREN_SUGAR)
+            }
+            _ => true,
+        };
+        if prohibit_parens && self.prohibit_parenthesized_generic_args() {
+            return TyBuilder::unknown_subst(self.ctx.db, def);
+        }
+
+        self.substs_from_args_and_bindings(
+            self.current_or_prev_segment.args_and_bindings,
+            def,
+            infer_args,
+            explicit_self_ty,
+        )
+    }
+
+    pub(super) fn substs_from_args_and_bindings(
+        &mut self,
+        args_and_bindings: Option<&GenericArgs>,
+        def: GenericDefId,
+        infer_args: bool,
+        explicit_self_ty: Option<Ty>,
+    ) -> Substitution {
+        // Order is
+        // - Optional Self parameter
+        // - Lifetime parameters
+        // - Type or Const parameters
+        // - Parent parameters
+        let def_generics = generics(self.ctx.db.upcast(), def);
+        let (
+            parent_params,
+            self_param,
+            type_params,
+            const_params,
+            impl_trait_params,
+            lifetime_params,
+        ) = def_generics.provenance_split();
+        let item_len =
+            self_param as usize + type_params + const_params + impl_trait_params + lifetime_params;
+        let total_len = parent_params + item_len;
+
+        let mut substs = Vec::new();
+
+        // we need to iterate the lifetime and type/const params separately as our order of them
+        // differs from the supplied syntax
+
+        let ty_error = || TyKind::Error.intern(Interner).cast(Interner);
+        let mut def_toc_iter = def_generics.iter_self_type_or_consts_id();
+        let fill_self_param = || {
+            if self_param {
+                let self_ty = explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(ty_error);
+
+                if let Some(id) = def_toc_iter.next() {
+                    assert!(matches!(id, GenericParamId::TypeParamId(_)));
+                    substs.push(self_ty);
+                }
+            }
+        };
+        let mut had_explicit_args = false;
+
+        if let Some(&GenericArgs { ref args, has_self_type, .. }) = args_and_bindings {
+            // Fill in the self param first
+            if has_self_type && self_param {
+                had_explicit_args = true;
+                if let Some(id) = def_toc_iter.next() {
+                    assert!(matches!(id, GenericParamId::TypeParamId(_)));
+                    had_explicit_args = true;
+                    if let GenericArg::Type(ty) = &args[0] {
+                        substs.push(self.ctx.lower_ty(*ty).cast(Interner));
+                    }
+                }
+            } else {
+                fill_self_param()
+            };
+
+            // Then fill in the supplied lifetime args, or error lifetimes if there are too few
+            // (default lifetimes aren't a thing)
+            for arg in args
+                .iter()
+                .filter_map(|arg| match arg {
+                    GenericArg::Lifetime(arg) => Some(self.ctx.lower_lifetime(arg)),
+                    _ => None,
+                })
+                .chain(iter::repeat(error_lifetime()))
+                .take(lifetime_params)
+            {
+                substs.push(arg.cast(Interner));
+            }
+
+            let skip = if has_self_type { 1 } else { 0 };
+            // Fill in supplied type and const args
+            // Note if non-lifetime args are provided, it should be all of them, but we can't rely on that
+            for (arg, id) in args
+                .iter()
+                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
+                .skip(skip)
+                .take(type_params + const_params)
+                .zip(def_toc_iter)
+            {
+                had_explicit_args = true;
+                let arg = generic_arg_to_chalk(
+                    self.ctx.db,
+                    id,
+                    arg,
+                    self.ctx,
+                    self.ctx.types_map,
+                    |ctx, type_ref| ctx.lower_ty(type_ref),
+                    |ctx, const_ref, ty| ctx.lower_const(const_ref, ty),
+                    |ctx, lifetime_ref| ctx.lower_lifetime(lifetime_ref),
+                );
+                substs.push(arg);
+            }
+        } else {
+            fill_self_param();
+        }
+
+        let param_to_err = |id| match id {
+            GenericParamId::ConstParamId(x) => {
+                unknown_const_as_generic(self.ctx.db.const_param_ty(x))
+            }
+            GenericParamId::TypeParamId(_) => ty_error(),
+            GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
+        };
+        // handle defaults. In expression or pattern path segments without
+        // explicitly specified type arguments, missing type arguments are inferred
+        // (i.e. defaults aren't used).
+        // Generic parameters for associated types are not supposed to have defaults, so we just
+        // ignore them.
+        let is_assoc_ty = || match def {
+            GenericDefId::TypeAliasId(id) => {
+                matches!(id.lookup(self.ctx.db.upcast()).container, ItemContainerId::TraitId(_))
+            }
+            _ => false,
+        };
+        let fill_defaults = (!infer_args || had_explicit_args) && !is_assoc_ty();
+        if fill_defaults {
+            let defaults = &*self.ctx.db.generic_defaults(def);
+            let (item, _parent) = defaults.split_at(item_len);
+            let parent_from = item_len - substs.len();
+
+            let mut rem =
+                def_generics.iter_id().skip(substs.len()).map(param_to_err).collect::<Vec<_>>();
+            // Fill in defaults for type/const params
+            for (idx, default_ty) in item[substs.len()..].iter().enumerate() {
+                // each default can depend on the previous parameters
+                let substs_so_far = Substitution::from_iter(
+                    Interner,
+                    substs.iter().cloned().chain(rem[idx..].iter().cloned()),
+                );
+                substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
+            }
+            // Fill in remaining parent params
+            substs.extend(rem.drain(parent_from..));
+        } else {
+            // Fill in remaining def params and parent params
+            substs.extend(def_generics.iter_id().skip(substs.len()).map(param_to_err));
+        }
+
+        assert_eq!(substs.len(), total_len, "expected {} substs, got {}", total_len, substs.len());
+        Substitution::from_iter(Interner, substs)
+    }
+
+    pub(crate) fn lower_trait_ref_from_resolved_path(
+        &mut self,
+        resolved: TraitId,
+        explicit_self_ty: Ty,
+    ) -> TraitRef {
+        let substs = self.trait_ref_substs_from_path(resolved, explicit_self_ty);
+        TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
+    }
+
+    fn trait_ref_substs_from_path(
+        &mut self,
+        resolved: TraitId,
+        explicit_self_ty: Ty,
+    ) -> Substitution {
+        self.substs_from_path_segment(resolved.into(), false, Some(explicit_self_ty))
+    }
+
+    pub(super) fn assoc_type_bindings_from_type_bound<'c>(
+        mut self,
+        bound: &'c TypeBound,
+        trait_ref: TraitRef,
+    ) -> Option<impl Iterator<Item = QuantifiedWhereClause> + use<'a, 'b, 'c>> {
+        self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
+            args_and_bindings.bindings.iter().flat_map(move |binding| {
+                let found = associated_type_by_name_including_super_traits(
+                    self.ctx.db,
+                    trait_ref.clone(),
+                    &binding.name,
+                );
+                let (super_trait_ref, associated_ty) = match found {
+                    None => return SmallVec::new(),
+                    Some(t) => t,
+                };
+                // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+                // generic params. It's inefficient to splice the `Substitution`s, so we may want
+                // that method to optionally take parent `Substitution` as we already know them at
+                // this point (`super_trait_ref.substitution`).
+                let substitution = self.substs_from_args_and_bindings(
+                    binding.args.as_ref(),
+                    associated_ty.into(),
+                    false, // this is not relevant
+                    Some(super_trait_ref.self_type_parameter(Interner)),
+                );
+                let self_params = generics(self.ctx.db.upcast(), associated_ty.into()).len_self();
+                let substitution = Substitution::from_iter(
+                    Interner,
+                    substitution
+                        .iter(Interner)
+                        .take(self_params)
+                        .chain(super_trait_ref.substitution.iter(Interner)),
+                );
+                let projection_ty = ProjectionTy {
+                    associated_ty_id: to_assoc_type_id(associated_ty),
+                    substitution,
+                };
+                let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
+                    binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
+                );
+                if let Some(type_ref) = binding.type_ref {
+                    match (&self.ctx.types_map[type_ref], self.ctx.impl_trait_mode.mode) {
+                        (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
+                        (_, ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque) => {
+                            let ty = self.ctx.lower_ty(type_ref);
+                            let alias_eq =
+                                AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
+                            predicates
+                                .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
+                        }
+                        (_, ImplTraitLoweringMode::Param | ImplTraitLoweringMode::Variable) => {
+                            // Find the generic index for the target of our `bound`
+                            let target_param_idx =
+                                self.ctx.resolver.where_predicates_in_scope().find_map(|(p, _)| {
+                                    match p {
+                                        WherePredicate::TypeBound {
+                                            target: WherePredicateTypeTarget::TypeOrConstParam(idx),
+                                            bound: b,
+                                        } if b == bound => Some(idx),
+                                        _ => None,
+                                    }
+                                });
+                            let ty = if let Some(target_param_idx) = target_param_idx {
+                                let mut counter = 0;
+                                let generics = self.ctx.generics().expect("generics in scope");
+                                for (idx, data) in generics.iter_self_type_or_consts() {
+                                    // Count the number of `impl Trait` things that appear before
+                                    // the target of our `bound`.
+                                    // Our counter within `impl_trait_mode` should be that number
+                                    // to properly lower each types within `type_ref`
+                                    if data.type_param().is_some_and(|p| {
+                                        p.provenance == TypeParamProvenance::ArgumentImplTrait
+                                    }) {
+                                        counter += 1;
+                                    }
+                                    if idx == *target_param_idx {
+                                        break;
+                                    }
+                                }
+                                let mut ext = TyLoweringContext::new_maybe_unowned(
+                                    self.ctx.db,
+                                    self.ctx.resolver,
+                                    self.ctx.types_map,
+                                    self.ctx.types_source_map,
+                                    self.ctx.owner,
+                                )
+                                .with_type_param_mode(self.ctx.type_param_mode);
+                                match self.ctx.impl_trait_mode.mode {
+                                    ImplTraitLoweringMode::Param => {
+                                        ext.impl_trait_mode =
+                                            ImplTraitLoweringState::param(counter);
+                                    }
+                                    ImplTraitLoweringMode::Variable => {
+                                        ext.impl_trait_mode =
+                                            ImplTraitLoweringState::variable(counter);
+                                    }
+                                    _ => unreachable!(),
+                                }
+                                let ty = ext.lower_ty(type_ref);
+                                self.ctx.diagnostics.extend(ext.diagnostics);
+                                ty
+                            } else {
+                                self.ctx.lower_ty(type_ref)
+                            };
+
+                            let alias_eq =
+                                AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
+                            predicates
+                                .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
+                        }
+                    }
+                }
+                for bound in binding.bounds.iter() {
+                    predicates.extend(self.ctx.lower_type_bound(
+                        bound,
+                        TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner),
+                        false,
+                    ));
+                }
+                predicates
+            })
+        })
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
index 84d8950b1aa..41304bbd8a9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -10,7 +10,7 @@ use crate::{
     lang_items::is_box,
     mapping::ToChalk,
     CallableDefId, ClosureId, Const, ConstScalar, InferenceResult, Interner, MemoryMap,
-    Substitution, TraitEnvironment, Ty, TyKind,
+    Substitution, TraitEnvironment, Ty, TyExt, TyKind,
 };
 use base_db::CrateId;
 use chalk_ir::Mutability;
@@ -144,6 +144,13 @@ impl<V, T> ProjectionElem<V, T> {
         closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty,
         krate: CrateId,
     ) -> Ty {
+        // we only bail on mir building when there are type mismatches
+        // but error types may pop up resulting in us still attempting to build the mir
+        // so just propagate the error type
+        if base.is_unknown() {
+            return TyKind::Error.intern(Interner);
+        }
+
         if matches!(base.kind(Interner), TyKind::Alias(_) | TyKind::AssociatedType(..)) {
             base = normalize(
                 db,
@@ -166,7 +173,7 @@ impl<V, T> ProjectionElem<V, T> {
                     TyKind::Error.intern(Interner)
                 }
             },
-            ProjectionElem::Field(Either::Left(f)) => match &base.kind(Interner) {
+            ProjectionElem::Field(Either::Left(f)) => match base.kind(Interner) {
                 TyKind::Adt(_, subst) => {
                     db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst)
                 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
index f1e86daea23..9625ae5f88e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
@@ -912,3 +912,36 @@ fn main() {
         "",
     );
 }
+
+#[test]
+fn regression_19021() {
+    check_pass(
+        r#"
+//- minicore: deref
+use core::ops::Deref;
+
+#[lang = "owned_box"]
+struct Box<T>(T);
+
+impl<T> Deref for Box<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+struct Foo;
+
+fn main() {
+    let x = Box(Foo);
+    let y = &Foo;
+
+    || match x {
+        ref x => x,
+        _ => y,
+    };
+}
+"#,
+    );
+}
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 549450e9beb..f88696692e6 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
@@ -8,8 +8,8 @@ use hir_def::{
     data::adt::{StructKind, VariantData},
     expr_store::{Body, HygieneId},
     hir::{
-        ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal,
-        LiteralOrConst, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField,
+        ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm,
+        Pat, PatId, RecordFieldPat, RecordLitField,
     },
     lang_item::{LangItem, LangItemTarget},
     path::Path,
@@ -1358,20 +1358,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
         Ok(())
     }
 
-    fn lower_literal_or_const_to_operand(
-        &mut self,
-        ty: Ty,
-        loc: &LiteralOrConst,
-    ) -> Result<Operand> {
-        match loc {
-            LiteralOrConst::Literal(l) => self.lower_literal_to_operand(ty, l),
-            LiteralOrConst::Const(c) => {
-                let c = match &self.body.pats[*c] {
-                    Pat::Path(p) => p,
-                    _ => not_supported!(
-                        "only `char` and numeric types are allowed in range patterns"
-                    ),
-                };
+    fn lower_literal_or_const_to_operand(&mut self, ty: Ty, loc: &ExprId) -> Result<Operand> {
+        match &self.body.exprs[*loc] {
+            Expr::Literal(l) => self.lower_literal_to_operand(ty, l),
+            Expr::Path(c) => {
                 let edition = self.edition();
                 let unresolved_name =
                     || MirLowerError::unresolved_path(self.db, c, edition, &self.body.types);
@@ -1392,6 +1382,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     }
                 }
             }
+            _ => {
+                not_supported!("only `char` and numeric types are allowed in range patterns");
+            }
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 2ffea34c85a..289175feefb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -1,6 +1,6 @@
 //! MIR lowering for patterns
 
-use hir_def::{hir::LiteralOrConst, AssocItemId};
+use hir_def::{hir::ExprId, AssocItemId};
 
 use crate::{
     mir::{
@@ -207,7 +207,7 @@ impl MirLowerCtx<'_> {
                 )?
             }
             Pat::Range { start, end } => {
-                let mut add_check = |l: &LiteralOrConst, binop| -> Result<()> {
+                let mut add_check = |l: &ExprId, binop| -> Result<()> {
                     let lv =
                         self.lower_literal_or_const_to_operand(self.infer[pattern].clone(), l)?;
                     let else_target = *current_else.get_or_insert_with(|| self.new_basic_block());
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 69ec35f406d..f5a4d4ff35c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -117,7 +117,7 @@ fn check_impl(
                     expected.trim_start_matches("adjustments:").trim().to_owned(),
                 );
             } else {
-                panic!("unexpected annotation: {expected}");
+                panic!("unexpected annotation: {expected} @ {range:?}");
             }
             had_annotations = true;
         }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
index 7992f1feeeb..ef94814d587 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
@@ -185,11 +185,10 @@ fn test() {
     let t = &mut 1;
     let x = match 1 {
         1 => t as *mut i32,
+           //^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer)
         2 => t as &i32,
            //^^^^^^^^^ expected *mut i32, got &'? i32
         _ => t as *const i32,
-          // ^^^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer)
-
     };
     x;
   //^ type: *const i32
@@ -536,7 +535,7 @@ fn test() {
 
 #[test]
 fn coerce_unsize_generic() {
-    check(
+    check_no_mismatches(
         r#"
 //- minicore: coerce_unsized
 struct Foo<T> { t: T };
@@ -544,9 +543,7 @@ struct Bar<T>(Foo<T>);
 
 fn test() {
     let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
-                         //^^^^^^^^^^^^^^^^^^^^^ expected &'? Foo<[usize]>, got &'? Foo<[i32; 3]>
     let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
-                         //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &'? Bar<[usize]>, got &'? Bar<[i32; 3]>
 }
 "#,
     );
@@ -958,3 +955,24 @@ fn f() {
     "#,
     );
 }
+
+#[test]
+fn coerce_nested_unsized_struct() {
+    check_types(
+        r#"
+//- minicore: fn, coerce_unsized, dispatch_from_dyn, sized
+use core::marker::Unsize;
+
+struct Foo<T: ?Sized>(T);
+
+fn need(_: &Foo<dyn Fn(i32) -> i32>) {
+}
+
+fn test() {
+    let callback = |x| x;
+                  //^ i32
+    need(&Foo(callback));
+}
+"#,
+    )
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
index def06f2d59d..855034117c0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
@@ -153,3 +153,53 @@ fn consume() -> Option<()> {
 "#,
     );
 }
+
+#[test]
+fn method_call_on_field() {
+    check(
+        r#"
+struct S {
+    field: fn(f32) -> u32,
+    field2: u32
+}
+
+fn main() {
+    let s = S { field: |_| 0, field2: 0 };
+    s.field(0);
+         // ^ expected f32, got i32
+ // ^^^^^^^^^^ type: u32
+    s.field2(0);
+          // ^ type: i32
+ // ^^^^^^^^^^^ type: {unknown}
+    s.not_a_field(0);
+               // ^ type: i32
+ // ^^^^^^^^^^^^^^^^ type: {unknown}
+}
+"#,
+    );
+}
+
+#[test]
+fn method_call_on_assoc() {
+    check(
+        r#"
+struct S;
+
+impl S {
+    fn not_a_method() -> f32 { 0.0 }
+    fn not_a_method2(this: Self, param: f32) -> Self { this }
+    fn not_a_method3(param: f32) -> Self { S }
+}
+
+fn main() {
+    S.not_a_method(0);
+ // ^^^^^^^^^^^^^^^^^ type: f32
+    S.not_a_method2(0);
+                 // ^ expected f32, got i32
+ // ^^^^^^^^^^^^^^^^^^ type: S
+    S.not_a_method3(0);
+ // ^^^^^^^^^^^^^^^^^^ type: S
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index e5f791ea6ff..3a258ecad10 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -1210,7 +1210,7 @@ impl<T> Slice<T> {
 fn main() {
     let foo: Slice<u32>;
     foo.into_vec(); // we shouldn't crash on this at least
-} //^^^^^^^^^^^^^^ {unknown}
+} //^^^^^^^^^^^^^^ ()
 "#,
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index dda7bfb2baf..f0eb41b1ce7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -4694,21 +4694,21 @@ fn f<T: Send, U>() {
     Struct::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^^^Yes
     Struct::<U>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^^^{unknown}
     Struct::<*const T>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^^{unknown}
     Enum::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^Yes
     Enum::<U>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^{unknown}
     Enum::<*const T>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^^^^^^^^{unknown}
     Union::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^^Yes
     Union::<U>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^^{unknown}
     Union::<*const T>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^{unknown}
     PhantomData::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^^^^^^^^Yes
     PhantomData::<U>::IS_SEND;
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 64e982c42d7..1ed0daa3756 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -6,10 +6,11 @@
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
 use hir_def::{
+    expr_store::ExprOrPatPtr,
     hir::ExprOrPatId,
     path::{hir_segment_to_ast_segment, ModPath},
     type_ref::TypesSourceMap,
-    AssocItemId, DefWithBodyId, SyntheticSyntax,
+    DefWithBodyId, SyntheticSyntax,
 };
 use hir_expand::{name::Name, HirFileId, InFile};
 use hir_ty::{
@@ -24,7 +25,7 @@ use syntax::{
 };
 use triomphe::Arc;
 
-use crate::{AssocItem, Field, Local, Trait, Type};
+use crate::{AssocItem, Field, Function, Local, Trait, Type};
 
 pub use hir_def::VariantId;
 pub use hir_ty::{
@@ -111,18 +112,19 @@ diagnostics![
     UnusedMut,
     UnusedVariable,
     GenericArgsProhibited,
+    ParenthesizedGenericArgsWithoutFnTrait,
 ];
 
 #[derive(Debug)]
 pub struct BreakOutsideOfLoop {
-    pub expr: InFile<AstPtr<ast::Expr>>,
+    pub expr: InFile<ExprOrPatPtr>,
     pub is_break: bool,
     pub bad_value_break: bool,
 }
 
 #[derive(Debug)]
 pub struct TypedHole {
-    pub expr: InFile<AstPtr<ast::Expr>>,
+    pub expr: InFile<ExprOrPatPtr>,
     pub expected: Type,
 }
 
@@ -221,26 +223,26 @@ pub struct NoSuchField {
 
 #[derive(Debug)]
 pub struct PrivateAssocItem {
-    pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
+    pub expr_or_pat: InFile<ExprOrPatPtr>,
     pub item: AssocItem,
 }
 
 #[derive(Debug)]
 pub struct MismatchedTupleStructPatArgCount {
-    pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
+    pub expr_or_pat: InFile<ExprOrPatPtr>,
     pub expected: usize,
     pub found: usize,
 }
 
 #[derive(Debug)]
 pub struct ExpectedFunction {
-    pub call: InFile<AstPtr<ast::Expr>>,
+    pub call: InFile<ExprOrPatPtr>,
     pub found: Type,
 }
 
 #[derive(Debug)]
 pub struct UnresolvedField {
-    pub expr: InFile<AstPtr<ast::Expr>>,
+    pub expr: InFile<ExprOrPatPtr>,
     pub receiver: Type,
     pub name: Name,
     pub method_with_same_name_exists: bool,
@@ -248,26 +250,26 @@ pub struct UnresolvedField {
 
 #[derive(Debug)]
 pub struct UnresolvedMethodCall {
-    pub expr: InFile<AstPtr<ast::Expr>>,
+    pub expr: InFile<ExprOrPatPtr>,
     pub receiver: Type,
     pub name: Name,
     pub field_with_same_name: Option<Type>,
-    pub assoc_func_with_same_name: Option<AssocItemId>,
+    pub assoc_func_with_same_name: Option<Function>,
 }
 
 #[derive(Debug)]
 pub struct UnresolvedAssocItem {
-    pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
+    pub expr_or_pat: InFile<ExprOrPatPtr>,
 }
 
 #[derive(Debug)]
 pub struct UnresolvedIdent {
-    pub node: InFile<(AstPtr<Either<ast::Expr, ast::Pat>>, Option<TextRange>)>,
+    pub node: InFile<(ExprOrPatPtr, Option<TextRange>)>,
 }
 
 #[derive(Debug)]
 pub struct PrivateField {
-    pub expr: InFile<AstPtr<ast::Expr>>,
+    pub expr: InFile<ExprOrPatPtr>,
     pub field: Field,
 }
 
@@ -280,7 +282,7 @@ pub enum UnsafeLint {
 
 #[derive(Debug)]
 pub struct MissingUnsafe {
-    pub node: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
+    pub node: InFile<ExprOrPatPtr>,
     pub lint: UnsafeLint,
     pub reason: UnsafetyReason,
 }
@@ -302,7 +304,7 @@ pub struct ReplaceFilterMapNextWithFindMap {
 
 #[derive(Debug)]
 pub struct MismatchedArgCount {
-    pub call_expr: InFile<AstPtr<ast::Expr>>,
+    pub call_expr: InFile<ExprOrPatPtr>,
     pub expected: usize,
     pub found: usize,
 }
@@ -321,7 +323,7 @@ pub struct NonExhaustiveLet {
 
 #[derive(Debug)]
 pub struct TypeMismatch {
-    pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
+    pub expr_or_pat: InFile<ExprOrPatPtr>,
     pub expected: Type,
     pub actual: Type,
 }
@@ -395,13 +397,13 @@ pub struct RemoveUnnecessaryElse {
 
 #[derive(Debug)]
 pub struct CastToUnsized {
-    pub expr: InFile<AstPtr<ast::Expr>>,
+    pub expr: InFile<ExprOrPatPtr>,
     pub cast_ty: Type,
 }
 
 #[derive(Debug)]
 pub struct InvalidCast {
-    pub expr: InFile<AstPtr<ast::Expr>>,
+    pub expr: InFile<ExprOrPatPtr>,
     pub error: CastError,
     pub expr_ty: Type,
     pub cast_ty: Type,
@@ -413,6 +415,11 @@ pub struct GenericArgsProhibited {
     pub reason: GenericArgsProhibitedReason,
 }
 
+#[derive(Debug)]
+pub struct ParenthesizedGenericArgsWithoutFnTrait {
+    pub args: InFile<AstPtr<ast::ParenthesizedArgList>>,
+}
+
 impl AnyDiagnostic {
     pub(crate) fn body_validation_diagnostic(
         db: &dyn HirDatabase,
@@ -428,9 +435,7 @@ impl AnyDiagnostic {
                     .collect();
 
                 let record = match record {
-                    Either::Left(record_expr) => {
-                        source_map.expr_syntax(record_expr).ok()?.map(AstPtr::wrap_left)
-                    }
+                    Either::Left(record_expr) => source_map.expr_syntax(record_expr).ok()?,
                     Either::Right(record_pat) => source_map.pat_syntax(record_pat).ok()?,
                 };
                 let file = record.file_id;
@@ -474,7 +479,7 @@ impl AnyDiagnostic {
                     return Some(
                         ReplaceFilterMapNextWithFindMap {
                             file: next_source_ptr.file_id,
-                            next_expr: next_source_ptr.value,
+                            next_expr: next_source_ptr.value.cast()?,
                         }
                         .into(),
                     );
@@ -484,7 +489,9 @@ impl AnyDiagnostic {
                 match source_map.expr_syntax(match_expr) {
                     Ok(source_ptr) => {
                         let root = source_ptr.file_syntax(db.upcast());
-                        if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) {
+                        if let Either::Left(ast::Expr::MatchExpr(match_expr)) =
+                            &source_ptr.value.to_node(&root)
+                        {
                             match match_expr.expr() {
                                 Some(scrut_expr) if match_expr.match_arm_list().is_some() => {
                                     return Some(
@@ -561,7 +568,7 @@ impl AnyDiagnostic {
         let pat_syntax =
             |pat| source_map.pat_syntax(pat).inspect_err(|_| stdx::never!("synthetic syntax")).ok();
         let expr_or_pat_syntax = |id| match id {
-            ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(|it| it.map(AstPtr::wrap_left)),
+            ExprOrPatId::ExprId(expr) => expr_syntax(expr),
             ExprOrPatId::PatId(pat) => pat_syntax(pat),
         };
         Some(match d {
@@ -622,7 +629,7 @@ impl AnyDiagnostic {
                     field_with_same_name: field_with_same_name
                         .clone()
                         .map(|ty| Type::new(db, def, ty)),
-                    assoc_func_with_same_name: *assoc_func_with_same_name,
+                    assoc_func_with_same_name: assoc_func_with_same_name.map(Into::into),
                 }
                 .into()
             }
@@ -633,7 +640,7 @@ impl AnyDiagnostic {
             &InferenceDiagnostic::UnresolvedIdent { id } => {
                 let node = match id {
                     ExprOrPatId::ExprId(id) => match source_map.expr_syntax(id) {
-                        Ok(syntax) => syntax.map(|it| (it.wrap_left(), None)),
+                        Ok(syntax) => syntax.map(|it| (it, None)),
                         Err(SyntheticSyntax) => source_map
                             .format_args_implicit_capture(id)?
                             .map(|(node, range)| (node.wrap_left(), Some(range))),
@@ -652,7 +659,7 @@ impl AnyDiagnostic {
             }
             &InferenceDiagnostic::MismatchedTupleStructPatArgCount { pat, expected, found } => {
                 let expr_or_pat = match pat {
-                    ExprOrPatId::ExprId(expr) => expr_syntax(expr)?.map(AstPtr::wrap_left),
+                    ExprOrPatId::ExprId(expr) => expr_syntax(expr)?,
                     ExprOrPatId::PatId(pat) => {
                         let InFile { file_id, value } = pat_syntax(pat)?;
 
@@ -702,8 +709,8 @@ impl AnyDiagnostic {
         diag: &PathLoweringDiagnostic,
         path: InFile<ast::Path>,
     ) -> Option<AnyDiagnostic> {
-        Some(match diag {
-            &PathLoweringDiagnostic::GenericArgsProhibited { segment, reason } => {
+        Some(match *diag {
+            PathLoweringDiagnostic::GenericArgsProhibited { segment, reason } => {
                 let segment = hir_segment_to_ast_segment(&path.value, segment)?;
                 let args = if let Some(generics) = segment.generic_arg_list() {
                     AstPtr::new(&generics).wrap_left()
@@ -713,6 +720,12 @@ impl AnyDiagnostic {
                 let args = path.with_value(args);
                 GenericArgsProhibited { args, reason }.into()
             }
+            PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment } => {
+                let segment = hir_segment_to_ast_segment(&path.value, segment)?;
+                let args = AstPtr::new(&segment.parenthesized_arg_list()?);
+                let args = path.with_value(args);
+                ParenthesizedGenericArgsWithoutFnTrait { args }.into()
+            }
         })
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs
index 537401afdc3..72df07ef8c0 100644
--- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs
@@ -49,6 +49,7 @@ from_id![
     (hir_def::LifetimeParamId, crate::LifetimeParam),
     (hir_def::MacroId, crate::Macro),
     (hir_def::ExternCrateId, crate::ExternCrateDecl),
+    (hir_def::ExternBlockId, crate::ExternBlock),
 ];
 
 impl From<AdtId> for Adt {
diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs
index 82c90ac3010..a34b4980832 100644
--- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs
@@ -248,7 +248,7 @@ impl HasSource for Param {
                 let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?;
                 let root = db.parse_or_expand(file_id);
                 match value.to_node(&root) {
-                    ast::Expr::ClosureExpr(it) => it
+                    Either::Left(ast::Expr::ClosureExpr(it)) => it
                         .param_list()?
                         .params()
                         .nth(self.idx)
@@ -301,7 +301,7 @@ impl HasSource for InlineAsmOperand {
             let root = src.file_syntax(db.upcast());
             return src
                 .map(|ast| match ast.to_node(&root) {
-                    ast::Expr::AsmExpr(asm) => asm
+                    Either::Left(ast::Expr::AsmExpr(asm)) => asm
                         .asm_pieces()
                         .filter_map(|it| match it {
                             ast::AsmPiece::AsmOperandNamed(it) => Some(it),
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 56090bc6b60..5923a1bc30e 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -55,8 +55,8 @@ use hir_def::{
     resolver::{HasResolver, Resolver},
     type_ref::TypesSourceMap,
     AdtId, AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId,
-    CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId,
-    GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstId, ItemContainerId,
+    CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId,
+    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstId, ItemContainerId,
     LifetimeParamId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
     SyntheticSyntax, TraitAliasId, TupleId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
 };
@@ -1957,7 +1957,7 @@ impl DefWithBody {
                 ExprOrPatId::PatId(pat) => source_map.pat_syntax(pat).map(Either::Right),
             };
             let expr_or_pat = match expr_or_pat {
-                Ok(Either::Left(expr)) => expr.map(AstPtr::wrap_left),
+                Ok(Either::Left(expr)) => expr,
                 Ok(Either::Right(InFile { file_id, value: pat })) => {
                     // cast from Either<Pat, SelfParam> -> Either<_, Pat>
                     let Some(ptr) = AstPtr::try_from_raw(pat.syntax_node_ptr()) else {
@@ -2003,7 +2003,7 @@ impl DefWithBody {
             match source_map.expr_syntax(node) {
                 Ok(node) => acc.push(
                     MissingUnsafe {
-                        node: node.map(|it| it.wrap_left()),
+                        node,
                         lint: UnsafeLint::DeprecatedSafe2024,
                         reason: UnsafetyReason::UnsafeFnCall,
                     }
@@ -2327,6 +2327,13 @@ impl Function {
         db.function_data(self.id).is_async()
     }
 
+    pub fn extern_block(self, db: &dyn HirDatabase) -> Option<ExternBlock> {
+        match self.id.lookup(db.upcast()).container {
+            ItemContainerId::ExternBlockId(id) => Some(ExternBlock { id }),
+            _ => None,
+        }
+    }
+
     pub fn returns_impl_future(self, db: &dyn HirDatabase) -> bool {
         if self.is_async(db) {
             return true;
@@ -2761,6 +2768,13 @@ impl Static {
         Type::from_value_def(db, self.id)
     }
 
+    pub fn extern_block(self, db: &dyn HirDatabase) -> Option<ExternBlock> {
+        match self.id.lookup(db.upcast()).container {
+            ItemContainerId::ExternBlockId(id) => Some(ExternBlock { id }),
+            _ => None,
+        }
+    }
+
     /// Evaluate the static initializer.
     pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst, ConstEvalError> {
         db.const_eval(self.id.into(), Substitution::empty(Interner), None)
@@ -2929,6 +2943,17 @@ impl HasVisibility for TypeAlias {
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ExternBlock {
+    pub(crate) id: ExternBlockId,
+}
+
+impl ExternBlock {
+    pub fn module(self, db: &dyn HirDatabase) -> Module {
+        Module { id: self.id.module(db.upcast()) }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct StaticLifetime;
 
 impl StaticLifetime {
@@ -4592,10 +4617,7 @@ impl CaptureUsages {
             match span {
                 mir::MirSpan::ExprId(expr) => {
                     if let Ok(expr) = source_map.expr_syntax(expr) {
-                        result.push(CaptureUsageSource {
-                            is_ref,
-                            source: expr.map(AstPtr::wrap_left),
-                        })
+                        result.push(CaptureUsageSource { is_ref, source: expr })
                     }
                 }
                 mir::MirSpan::PatId(pat) => {
@@ -6180,9 +6202,15 @@ impl HasContainer for TraitAlias {
     }
 }
 
+impl HasContainer for ExternBlock {
+    fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+        ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container })
+    }
+}
+
 fn container_id_to_hir(c: ItemContainerId) -> ItemContainer {
     match c {
-        ItemContainerId::ExternBlockId(_id) => ItemContainer::ExternBlock(),
+        ItemContainerId::ExternBlockId(id) => ItemContainer::ExternBlock(ExternBlock { id }),
         ItemContainerId::ModuleId(id) => ItemContainer::Module(Module { id }),
         ItemContainerId::ImplId(id) => ItemContainer::Impl(Impl { id }),
         ItemContainerId::TraitId(id) => ItemContainer::Trait(Trait { id }),
@@ -6194,7 +6222,7 @@ pub enum ItemContainer {
     Trait(Trait),
     Impl(Impl),
     Module(Module),
-    ExternBlock(),
+    ExternBlock(ExternBlock),
     Crate(CrateId),
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 882a27182f0..c9145f7d212 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -1998,6 +1998,7 @@ to_def_impls![
     (crate::Adt, ast::Adt, adt_to_def),
     (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def),
     (crate::InlineAsmOperand, ast::AsmOperandNamed, asm_operand_to_def),
+    (crate::ExternBlock, ast::ExternBlock, extern_block_to_def),
     (MacroCallId, ast::MacroCall, macro_call_to_macro_call),
 ];
 
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 d5dfb985718..d0fdf5cbdf7 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
@@ -74,6 +74,9 @@ impl ChildBySource for ItemScope {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
         self.declarations().for_each(|item| add_module_def(db, res, file_id, item));
         self.impls().for_each(|imp| insert_item_loc(db, res, file_id, imp, keys::IMPL));
+        self.extern_blocks().for_each(|extern_block| {
+            insert_item_loc(db, res, file_id, extern_block, keys::EXTERN_BLOCK)
+        });
         self.extern_crate_decls()
             .for_each(|ext| insert_item_loc(db, res, file_id, ext, keys::EXTERN_CRATE));
         self.use_decls().for_each(|ext| insert_item_loc(db, res, file_id, ext, keys::USE));
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index 3c9e7065c41..4481b8855fd 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -92,10 +92,10 @@ use hir_def::{
         DynMap,
     },
     hir::{BindingId, Expr, LabelId},
-    AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId,
-    FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, Lookup, MacroId,
-    ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, UseId,
-    VariantId,
+    AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
+    ExternCrateId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId,
+    Lookup, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId,
+    UnionId, UseId, VariantId,
 };
 use hir_expand::{
     attrs::AttrId, name::AsName, ExpansionInfo, HirFileId, HirFileIdExt, InMacroFile, MacroCallId,
@@ -308,6 +308,12 @@ impl SourceToDefCtx<'_, '_> {
     ) -> Option<ExternCrateId> {
         self.to_def(src, keys::EXTERN_CRATE)
     }
+    pub(super) fn extern_block_to_def(
+        &mut self,
+        src: InFile<&ast::ExternBlock>,
+    ) -> Option<ExternBlockId> {
+        self.to_def(src, keys::EXTERN_BLOCK)
+    }
     #[allow(dead_code)]
     pub(super) fn use_to_def(&mut self, src: InFile<&ast::Use>) -> Option<UseId> {
         self.to_def(src, keys::USE)
@@ -352,7 +358,7 @@ impl SourceToDefCtx<'_, '_> {
         let src = src.cloned().map(ast::Pat::from);
         let pat_id = source_map.node_pat(src.as_ref())?;
         // the pattern could resolve to a constant, verify that this is not the case
-        if let crate::Pat::Bind { id, .. } = body[pat_id] {
+        if let crate::Pat::Bind { id, .. } = body[pat_id.as_pat()?] {
             Some((container, id))
         } else {
             None
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 23e7518883b..9019863f7fd 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -18,7 +18,7 @@ use hir_def::{
         scope::{ExprScopes, ScopeId},
         Body, BodySourceMap, HygieneId,
     },
-    hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat, PatId},
+    hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
     lang_item::LangItem,
     lower::LowerCtx,
     nameres::MacroSubNs,
@@ -139,7 +139,7 @@ impl SourceAnalyzer {
         sm.node_expr(src.as_ref())
     }
 
-    fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
+    fn pat_id(&self, pat: &ast::Pat) -> Option<ExprOrPatId> {
         // FIXME: macros, see `expr_id`
         let src = InFile { file_id: self.file_id, value: pat };
         self.body_source_map()?.node_pat(src)
@@ -147,7 +147,7 @@ impl SourceAnalyzer {
 
     fn binding_id_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingId> {
         let pat_id = self.pat_id(&pat.clone().into())?;
-        if let Pat::Bind { id, .. } = self.body()?.pats[pat_id] {
+        if let Pat::Bind { id, .. } = self.body()?.pats[pat_id.as_pat()?] {
             Some(id)
         } else {
             None
@@ -210,11 +210,20 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         pat: &ast::Pat,
     ) -> Option<(Type, Option<Type>)> {
-        let pat_id = self.pat_id(pat)?;
+        let expr_or_pat_id = self.pat_id(pat)?;
         let infer = self.infer.as_ref()?;
-        let coerced =
-            infer.pat_adjustments.get(&pat_id).and_then(|adjusts| adjusts.last().cloned());
-        let ty = infer[pat_id].clone();
+        let coerced = match expr_or_pat_id {
+            ExprOrPatId::ExprId(idx) => infer
+                .expr_adjustments
+                .get(&idx)
+                .and_then(|adjusts| adjusts.last().cloned())
+                .map(|adjust| adjust.target),
+            ExprOrPatId::PatId(idx) => {
+                infer.pat_adjustments.get(&idx).and_then(|adjusts| adjusts.last().cloned())
+            }
+        };
+
+        let ty = infer[expr_or_pat_id].clone();
         let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
         Some((mk_ty(ty), coerced.map(mk_ty)))
     }
@@ -248,7 +257,7 @@ impl SourceAnalyzer {
     ) -> Option<BindingMode> {
         let id = self.pat_id(&pat.clone().into())?;
         let infer = self.infer.as_ref()?;
-        infer.binding_modes.get(id).map(|bm| match bm {
+        infer.binding_modes.get(id.as_pat()?).map(|bm| match bm {
             hir_ty::BindingMode::Move => BindingMode::Move,
             hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
             hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
@@ -266,7 +275,7 @@ impl SourceAnalyzer {
         Some(
             infer
                 .pat_adjustments
-                .get(&pat_id)?
+                .get(&pat_id.as_pat()?)?
                 .iter()
                 .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone()))
                 .collect(),
@@ -649,10 +658,10 @@ impl SourceAnalyzer {
         let field_name = field.field_name()?.as_name();
         let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
         let pat_id = self.pat_id(&record_pat.into())?;
-        let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?;
+        let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id.as_pat()?)?;
         let variant_data = variant.variant_data(db.upcast());
         let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
-        let (adt, subst) = self.infer.as_ref()?.type_of_pat.get(pat_id)?.as_adt()?;
+        let (adt, subst) = self.infer.as_ref()?.type_of_pat.get(pat_id.as_pat()?)?.as_adt()?;
         let field_ty =
             db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
         Some((
@@ -682,12 +691,20 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         pat: &ast::IdentPat,
     ) -> Option<ModuleDef> {
-        let pat_id = self.pat_id(&pat.clone().into())?;
+        let expr_or_pat_id = self.pat_id(&pat.clone().into())?;
         let body = self.body()?;
-        let path = match &body[pat_id] {
-            Pat::Path(path) => path,
-            _ => return None,
+
+        let path = match expr_or_pat_id {
+            ExprOrPatId::ExprId(idx) => match &body[idx] {
+                Expr::Path(path) => path,
+                _ => return None,
+            },
+            ExprOrPatId::PatId(idx) => match &body[idx] {
+                Pat::Path(path) => path,
+                _ => return None,
+            },
         };
+
         let res = resolve_hir_path(db, &self.resolver, path, HygieneId::ROOT, TypesMap::EMPTY)?;
         match res {
             PathResolution::Def(def) => Some(def),
@@ -782,8 +799,9 @@ impl SourceAnalyzer {
                 }
                 prefer_value_ns = true;
             } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
-                let pat_id = self.pat_id(&path_pat.into())?;
-                if let Some((assoc, subs)) = infer.assoc_resolutions_for_pat(pat_id) {
+                let expr_or_pat_id = self.pat_id(&path_pat.into())?;
+                if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr_or_pat(expr_or_pat_id)
+                {
                     let (assoc, subst) = match assoc {
                         AssocItemId::ConstId(const_id) => {
                             let (konst, subst) =
@@ -807,7 +825,7 @@ impl SourceAnalyzer {
                     return Some((PathResolution::Def(AssocItem::from(assoc).into()), Some(subst)));
                 }
                 if let Some(VariantId::EnumVariantId(variant)) =
-                    infer.variant_resolution_for_pat(pat_id)
+                    infer.variant_resolution_for_expr_or_pat(expr_or_pat_id)
                 {
                     return Some((PathResolution::Def(ModuleDef::Variant(variant.into())), None));
                 }
@@ -824,7 +842,7 @@ impl SourceAnalyzer {
                     || parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from);
                 if let Some(pat) = record_pat.or_else(tuple_struct_pat) {
                     let pat_id = self.pat_id(&pat)?;
-                    let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id);
+                    let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id.as_pat()?);
                     if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat {
                         return Some((
                             PathResolution::Def(ModuleDef::Variant(variant.into())),
@@ -866,7 +884,8 @@ impl SourceAnalyzer {
 
         // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
         // trying to resolve foo::bar.
-        if path.parent_path().is_some() {
+        if let Some(parent_path) = path.parent_path() {
+            let parent_hir_path = Path::from_src(&mut ctx, parent_path);
             return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map) {
                 None if meta_path.is_some() => path
                     .first_segment()
@@ -876,6 +895,42 @@ impl SourceAnalyzer {
                             .map(PathResolution::ToolModule)
                     })
                     .map(|it| (it, None)),
+                // Case the type name conflict with use module,
+                // e.g.
+                // ```
+                // use std::str;
+                // fn main() {
+                //     str::from_utf8();  // as module std::str
+                //     str::len();        // as primitive type str
+                //     str::no_exist_item(); // as primitive type str
+                // }
+                // ```
+                Some(it) if matches!(it, PathResolution::Def(ModuleDef::BuiltinType(_))) => {
+                    if let (Some(mod_path), Some(parent_hir_path)) =
+                        (hir_path.mod_path(), parent_hir_path)
+                    {
+                        if let Some(ModuleDefId::ModuleId(id)) = self
+                            .resolver
+                            .resolve_module_path_in_items(db.upcast(), mod_path)
+                            .take_types()
+                        {
+                            let parent_hir_name =
+                                parent_hir_path.segments().get(1).map(|it| it.name);
+                            let module = crate::Module { id };
+                            if module
+                                .scope(db, None)
+                                .into_iter()
+                                .any(|(name, _)| Some(&name) == parent_hir_name)
+                            {
+                                return Some((
+                                    PathResolution::Def(ModuleDef::Module(module)),
+                                    None,
+                                ));
+                            };
+                        }
+                    }
+                    Some((it, None))
+                }
                 // FIXME: We do not show substitutions for parts of path, because this is really complex
                 // due to the interactions with associated items of `impl`s and associated items of associated
                 // types.
@@ -1043,7 +1098,7 @@ impl SourceAnalyzer {
         let body = self.body()?;
         let infer = self.infer.as_ref()?;
 
-        let pat_id = self.pat_id(&pattern.clone().into())?;
+        let pat_id = self.pat_id(&pattern.clone().into())?.as_pat()?;
         let substs = infer.type_of_pat[pat_id].as_adt()?.1;
 
         let (variant, missing_fields, _exhaustive) =
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 5899ec5a005..4a9e2256e9b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -6,7 +6,9 @@ use ide_db::syntax_helpers::suggest_name;
 use ide_db::RootDatabase;
 use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
 use itertools::Itertools;
-use syntax::ast::edit_in_place::Removable;
+use syntax::ast::edit::IndentLevel;
+use syntax::ast::edit_in_place::Indent;
+use syntax::ast::syntax_factory::SyntaxFactory;
 use syntax::ast::{self, make, AstNode, MatchArmList, MatchExpr, Pat};
 
 use crate::{utils, AssistContext, AssistId, AssistKind, Assists};
@@ -200,8 +202,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
         AssistId("add_missing_match_arms", AssistKind::QuickFix),
         "Fill match arms",
         ctx.sema.original_range(match_expr.syntax()).range,
-        |edit| {
-            let new_match_arm_list = match_arm_list.clone_for_update();
+        |builder| {
+            let make = SyntaxFactory::new();
 
             // having any hidden variants means that we need a catch-all arm
             needs_catch_all_arm |= has_hidden_variants;
@@ -211,89 +213,85 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
                     // filter out hidden patterns because they're handled by the catch-all arm
                     !hidden
                 })
-                .map(|(pat, _)| {
-                    make::match_arm(pat, None, make::ext::expr_todo()).clone_for_update()
-                });
+                .map(|(pat, _)| make.match_arm(pat, None, make::ext::expr_todo()));
 
-            let catch_all_arm = new_match_arm_list
+            let mut arms: Vec<_> = match_arm_list
                 .arms()
-                .find(|arm| matches!(arm.pat(), Some(ast::Pat::WildcardPat(_))));
-            if let Some(arm) = catch_all_arm {
-                let is_empty_expr = arm.expr().is_none_or(|e| match e {
-                    ast::Expr::BlockExpr(b) => {
-                        b.statements().next().is_none() && b.tail_expr().is_none()
+                .filter(|arm| {
+                    if matches!(arm.pat(), Some(ast::Pat::WildcardPat(_))) {
+                        let is_empty_expr = arm.expr().is_none_or(|e| match e {
+                            ast::Expr::BlockExpr(b) => {
+                                b.statements().next().is_none() && b.tail_expr().is_none()
+                            }
+                            ast::Expr::TupleExpr(t) => t.fields().next().is_none(),
+                            _ => false,
+                        });
+                        if is_empty_expr {
+                            false
+                        } else {
+                            cov_mark::hit!(add_missing_match_arms_empty_expr);
+                            true
+                        }
+                    } else {
+                        true
                     }
-                    ast::Expr::TupleExpr(t) => t.fields().next().is_none(),
-                    _ => false,
-                });
-                if is_empty_expr {
-                    arm.remove();
-                } else {
-                    cov_mark::hit!(add_missing_match_arms_empty_expr);
-                }
-            }
+                })
+                .collect();
 
-            let mut added_arms = Vec::new();
-            let mut todo_placeholders = Vec::new();
-            for arm in missing_arms {
-                todo_placeholders.push(arm.expr().unwrap());
-                added_arms.push(arm);
-            }
+            let first_new_arm_idx = arms.len();
+            arms.extend(missing_arms);
 
             if needs_catch_all_arm && !has_catch_all_arm {
                 cov_mark::hit!(added_wildcard_pattern);
-                let arm =
-                    make::match_arm(make::wildcard_pat().into(), None, make::ext::expr_todo())
-                        .clone_for_update();
-                todo_placeholders.push(arm.expr().unwrap());
-                added_arms.push(arm);
-            }
-
-            let first_new_arm = added_arms.first().cloned();
-            let last_new_arm = added_arms.last().cloned();
-
-            for arm in added_arms {
-                new_match_arm_list.add_arm(arm);
+                let arm = make.match_arm(make::wildcard_pat().into(), None, make::ext::expr_todo());
+                arms.push(arm);
             }
 
-            if let Some(cap) = ctx.config.snippet_cap {
-                if let Some(it) = first_new_arm
-                    .and_then(|arm| arm.syntax().descendants().find_map(ast::WildcardPat::cast))
-                {
-                    edit.add_placeholder_snippet(cap, it);
-                }
-
-                for placeholder in todo_placeholders {
-                    edit.add_placeholder_snippet(cap, placeholder);
-                }
-
-                if let Some(arm) = last_new_arm {
-                    edit.add_tabstop_after(cap, arm);
-                }
-            }
+            let new_match_arm_list = make.match_arm_list(arms);
 
-            // FIXME: Hack for mutable syntax trees not having great support for macros
+            // FIXME: Hack for syntax trees not having great support for macros
             // Just replace the element that the original range came from
             let old_place = {
                 // Find the original element
                 let file = ctx.sema.parse(arm_list_range.file_id);
                 let old_place = file.syntax().covering_element(arm_list_range.range);
 
-                // Make `old_place` mut
                 match old_place {
-                    syntax::SyntaxElement::Node(it) => {
-                        syntax::SyntaxElement::from(edit.make_syntax_mut(it))
-                    }
+                    syntax::SyntaxElement::Node(it) => it,
                     syntax::SyntaxElement::Token(it) => {
                         // If a token is found, it is '{' or '}'
                         // The parent is `{ ... }`
-                        let parent = it.parent().expect("Token must have a parent.");
-                        syntax::SyntaxElement::from(edit.make_syntax_mut(parent))
+                        it.parent().expect("Token must have a parent.")
                     }
                 }
             };
 
-            syntax::ted::replace(old_place, new_match_arm_list.syntax());
+            let mut editor = builder.make_editor(&old_place);
+            new_match_arm_list.indent(IndentLevel::from_node(&old_place));
+            editor.replace(old_place, new_match_arm_list.syntax());
+
+            if let Some(cap) = ctx.config.snippet_cap {
+                if let Some(it) = new_match_arm_list
+                    .arms()
+                    .nth(first_new_arm_idx)
+                    .and_then(|arm| arm.syntax().descendants().find_map(ast::WildcardPat::cast))
+                {
+                    editor.add_annotation(it.syntax(), builder.make_placeholder_snippet(cap));
+                }
+
+                for arm in new_match_arm_list.arms().skip(first_new_arm_idx) {
+                    if let Some(expr) = arm.expr() {
+                        editor.add_annotation(expr.syntax(), builder.make_placeholder_snippet(cap));
+                    }
+                }
+
+                if let Some(arm) = new_match_arm_list.arms().skip(first_new_arm_idx).last() {
+                    editor.add_annotation(arm.syntax(), builder.make_tabstop_after(cap));
+                }
+            }
+
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.file_id(), editor);
         },
     )
 }
@@ -1377,6 +1375,9 @@ fn main() {
         );
     }
 
+    // FIXME: Preserving comments is quite hard in the current transitional syntax editing model.
+    // Once we migrate to new trivia model addressed in #6854, remove the ignore attribute.
+    #[ignore]
     #[test]
     fn add_missing_match_arms_preserves_comments() {
         check_assist(
@@ -1405,6 +1406,9 @@ fn foo(a: A) {
         );
     }
 
+    // FIXME: Preserving comments is quite hard in the current transitional syntax editing model.
+    // Once we migrate to new trivia model addressed in #6854, remove the ignore attribute.
+    #[ignore]
     #[test]
     fn add_missing_match_arms_preserves_comments_empty() {
         check_assist(
@@ -1502,10 +1506,10 @@ enum Test {
 
 fn foo(t: Test) {
     m!(match t {
-    Test::A => ${1:todo!()},
-    Test::B => ${2:todo!()},
-    Test::C => ${3:todo!()},$0
-});
+        Test::A => ${1:todo!()},
+        Test::B => ${2:todo!()},
+        Test::C => ${3:todo!()},$0
+    });
 }"#,
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
index 094fdc46eb7..0b95d6177f9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
@@ -3,10 +3,11 @@ use hir::{AssocItem, Enum, HasVisibility, Module, ModuleDef, Name, PathResolutio
 use ide_db::{
     defs::{Definition, NameRefClass},
     search::SearchScope,
+    source_change::SourceChangeBuilder,
 };
 use stdx::never;
 use syntax::{
-    ast::{self, make},
+    ast::{self, make, Use, UseTree, VisibilityKind},
     ted, AstNode, Direction, SyntaxNode, SyntaxToken, T,
 };
 
@@ -43,6 +44,7 @@ use crate::{
 pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let star = ctx.find_token_syntax_at_offset(T![*])?;
     let use_tree = star.parent().and_then(ast::UseTree::cast)?;
+    let use_item = star.parent_ancestors().find_map(ast::Use::cast)?;
     let (parent, mod_path) = find_parent_and_path(&star)?;
     let target_module = match ctx.sema.resolve_path(&mod_path)? {
         PathResolution::Def(ModuleDef::Module(it)) => Expandable::Module(it),
@@ -53,8 +55,9 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     let current_scope = ctx.sema.scope(&star.parent()?)?;
     let current_module = current_scope.module();
 
-    let refs_in_target = find_refs_in_mod(ctx, target_module, current_module)?;
-    let imported_defs = find_imported_defs(ctx, star)?;
+    if !is_visible_from(ctx, &target_module, current_module) {
+        return None;
+    }
 
     let target = parent.either(|n| n.syntax().clone(), |n| n.syntax().clone());
     acc.add(
@@ -62,37 +65,149 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) ->
         "Expand glob import",
         target.text_range(),
         |builder| {
-            let use_tree = builder.make_mut(use_tree);
-
-            let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs);
-            let expanded = make::use_tree_list(names_to_import.iter().map(|n| {
-                let path = make::ext::ident_path(
-                    &n.display(ctx.db(), current_module.krate().edition(ctx.db())).to_string(),
-                );
-                make::use_tree(path, None, None, false)
-            }))
-            .clone_for_update();
-
-            match use_tree.star_token() {
-                Some(star) => {
-                    let needs_braces = use_tree.path().is_some() && names_to_import.len() != 1;
-                    if needs_braces {
-                        ted::replace(star, expanded.syntax())
-                    } else {
-                        let without_braces = expanded
-                            .syntax()
-                            .children_with_tokens()
-                            .filter(|child| !matches!(child.kind(), T!['{'] | T!['}']))
-                            .collect();
-                        ted::replace_with_many(star, without_braces)
-                    }
-                }
-                None => never!(),
-            }
+            build_expanded_import(
+                ctx,
+                builder,
+                use_tree,
+                use_item,
+                target_module,
+                current_module,
+                false,
+            )
+        },
+    )
+}
+
+// Assist: expand_glob_reexport
+//
+// Expands non-private glob imports.
+//
+// ```
+// mod foo {
+//     pub struct Bar;
+//     pub struct Baz;
+// }
+//
+// pub use foo::*$0;
+// ```
+// ->
+// ```
+// mod foo {
+//     pub struct Bar;
+//     pub struct Baz;
+// }
+//
+// pub use foo::{Bar, Baz};
+// ```
+pub(crate) fn expand_glob_reexport(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let star = ctx.find_token_syntax_at_offset(T![*])?;
+    let use_tree = star.parent().and_then(ast::UseTree::cast)?;
+    let use_item = star.parent_ancestors().find_map(ast::Use::cast)?;
+    let (parent, mod_path) = find_parent_and_path(&star)?;
+    let target_module = match ctx.sema.resolve_path(&mod_path)? {
+        PathResolution::Def(ModuleDef::Module(it)) => Expandable::Module(it),
+        PathResolution::Def(ModuleDef::Adt(hir::Adt::Enum(e))) => Expandable::Enum(e),
+        _ => return None,
+    };
+
+    let current_scope = ctx.sema.scope(&star.parent()?)?;
+    let current_module = current_scope.module();
+
+    if let VisibilityKind::PubSelf = get_export_visibility_kind(&use_item) {
+        return None;
+    }
+    if !is_visible_from(ctx, &target_module, current_module) {
+        return None;
+    }
+
+    let target = parent.either(|n| n.syntax().clone(), |n| n.syntax().clone());
+    acc.add(
+        AssistId("expand_glob_reexport", AssistKind::RefactorRewrite),
+        "Expand glob reexport",
+        target.text_range(),
+        |builder| {
+            build_expanded_import(
+                ctx,
+                builder,
+                use_tree,
+                use_item,
+                target_module,
+                current_module,
+                true,
+            )
         },
     )
 }
 
+fn build_expanded_import(
+    ctx: &AssistContext<'_>,
+    builder: &mut SourceChangeBuilder,
+    use_tree: UseTree,
+    use_item: Use,
+    target_module: Expandable,
+    current_module: Module,
+    reexport_public_items: bool,
+) {
+    let (must_be_pub, visible_from) = if !reexport_public_items {
+        (false, current_module)
+    } else {
+        match get_export_visibility_kind(&use_item) {
+            VisibilityKind::Pub => (true, current_module.krate().root_module()),
+            VisibilityKind::PubCrate => (false, current_module.krate().root_module()),
+            _ => (false, current_module),
+        }
+    };
+
+    let refs_in_target = find_refs_in_mod(ctx, target_module, visible_from, must_be_pub);
+    let imported_defs = find_imported_defs(ctx, use_item);
+
+    let filtered_defs =
+        if reexport_public_items { refs_in_target } else { refs_in_target.used_refs(ctx) };
+
+    let use_tree = builder.make_mut(use_tree);
+
+    let names_to_import = find_names_to_import(filtered_defs, imported_defs);
+    let expanded = make::use_tree_list(names_to_import.iter().map(|n| {
+        let path = make::ext::ident_path(
+            &n.display(ctx.db(), current_module.krate().edition(ctx.db())).to_string(),
+        );
+        make::use_tree(path, None, None, false)
+    }))
+    .clone_for_update();
+
+    match use_tree.star_token() {
+        Some(star) => {
+            let needs_braces = use_tree.path().is_some() && names_to_import.len() != 1;
+            if needs_braces {
+                ted::replace(star, expanded.syntax())
+            } else {
+                let without_braces = expanded
+                    .syntax()
+                    .children_with_tokens()
+                    .filter(|child| !matches!(child.kind(), T!['{'] | T!['}']))
+                    .collect();
+                ted::replace_with_many(star, without_braces)
+            }
+        }
+        None => never!(),
+    }
+}
+
+fn get_export_visibility_kind(use_item: &Use) -> VisibilityKind {
+    use syntax::ast::HasVisibility as _;
+    match use_item.visibility() {
+        Some(vis) => match vis.kind() {
+            VisibilityKind::PubCrate => VisibilityKind::PubCrate,
+            VisibilityKind::Pub => VisibilityKind::Pub,
+            VisibilityKind::PubSelf => VisibilityKind::PubSelf,
+            // We don't handle pub(in ...) and pub(super) yet
+            VisibilityKind::In(_) => VisibilityKind::PubSelf,
+            VisibilityKind::PubSuper => VisibilityKind::PubSelf,
+        },
+        None => VisibilityKind::PubSelf,
+    }
+}
+
 enum Expandable {
     Module(Module),
     Enum(Enum),
@@ -130,14 +245,17 @@ struct Ref {
     // could be alias
     visible_name: Name,
     def: Definition,
+    is_pub: bool,
 }
 
 impl Ref {
-    fn from_scope_def(name: Name, scope_def: ScopeDef) -> Option<Self> {
+    fn from_scope_def(ctx: &AssistContext<'_>, name: Name, scope_def: ScopeDef) -> Option<Self> {
         match scope_def {
-            ScopeDef::ModuleDef(def) => {
-                Some(Ref { visible_name: name, def: Definition::from(def) })
-            }
+            ScopeDef::ModuleDef(def) => Some(Ref {
+                visible_name: name,
+                def: Definition::from(def),
+                is_pub: matches!(def.visibility(ctx.db()), hir::Visibility::Public),
+            }),
             _ => None,
         }
     }
@@ -180,32 +298,32 @@ fn find_refs_in_mod(
     ctx: &AssistContext<'_>,
     expandable: Expandable,
     visible_from: Module,
-) -> Option<Refs> {
-    if !is_expandable_visible_from(ctx, &expandable, visible_from) {
-        return None;
-    }
-
+    must_be_pub: bool,
+) -> Refs {
     match expandable {
         Expandable::Module(module) => {
             let module_scope = module.scope(ctx.db(), Some(visible_from));
-            let refs =
-                module_scope.into_iter().filter_map(|(n, d)| Ref::from_scope_def(n, d)).collect();
-            Some(Refs(refs))
+            let refs = module_scope
+                .into_iter()
+                .filter_map(|(n, d)| Ref::from_scope_def(ctx, n, d))
+                .filter(|r| !must_be_pub || r.is_pub)
+                .collect();
+            Refs(refs)
         }
-        Expandable::Enum(enm) => Some(Refs(
+        Expandable::Enum(enm) => Refs(
             enm.variants(ctx.db())
                 .into_iter()
-                .map(|v| Ref { visible_name: v.name(ctx.db()), def: Definition::Variant(v) })
+                .map(|v| Ref {
+                    visible_name: v.name(ctx.db()),
+                    def: Definition::Variant(v),
+                    is_pub: true,
+                })
                 .collect(),
-        )),
+        ),
     }
 }
 
-fn is_expandable_visible_from(
-    ctx: &AssistContext<'_>,
-    expandable: &Expandable,
-    from: Module,
-) -> bool {
+fn is_visible_from(ctx: &AssistContext<'_>, expandable: &Expandable, from: Module) -> bool {
     fn is_mod_visible_from(ctx: &AssistContext<'_>, module: Module, from: Module) -> bool {
         match module.parent(ctx.db()) {
             Some(parent) => {
@@ -246,50 +364,34 @@ fn is_expandable_visible_from(
 // use foo::*$0;
 // use baz::Baz;
 // ↑ ---------------
-fn find_imported_defs(ctx: &AssistContext<'_>, star: SyntaxToken) -> Option<Vec<Definition>> {
-    let parent_use_item_syntax = star.parent_ancestors().find_map(|n| {
-        if ast::Use::can_cast(n.kind()) {
-            Some(n)
-        } else {
-            None
-        }
-    })?;
-
-    Some(
-        [Direction::Prev, Direction::Next]
-            .into_iter()
-            .flat_map(|dir| {
-                parent_use_item_syntax
-                    .siblings(dir.to_owned())
-                    .filter(|n| ast::Use::can_cast(n.kind()))
-            })
-            .flat_map(|n| n.descendants().filter_map(ast::NameRef::cast))
-            .filter_map(|r| match NameRefClass::classify(&ctx.sema, &r)? {
-                NameRefClass::Definition(
-                    def @ (Definition::Macro(_)
-                    | Definition::Module(_)
-                    | Definition::Function(_)
-                    | Definition::Adt(_)
-                    | Definition::Variant(_)
-                    | Definition::Const(_)
-                    | Definition::Static(_)
-                    | Definition::Trait(_)
-                    | Definition::TypeAlias(_)),
-                    _,
-                ) => Some(def),
-                _ => None,
-            })
-            .collect(),
-    )
+fn find_imported_defs(ctx: &AssistContext<'_>, use_item: Use) -> Vec<Definition> {
+    [Direction::Prev, Direction::Next]
+        .into_iter()
+        .flat_map(|dir| {
+            use_item.syntax().siblings(dir.to_owned()).filter(|n| ast::Use::can_cast(n.kind()))
+        })
+        .flat_map(|n| n.descendants().filter_map(ast::NameRef::cast))
+        .filter_map(|r| match NameRefClass::classify(&ctx.sema, &r)? {
+            NameRefClass::Definition(
+                def @ (Definition::Macro(_)
+                | Definition::Module(_)
+                | Definition::Function(_)
+                | Definition::Adt(_)
+                | Definition::Variant(_)
+                | Definition::Const(_)
+                | Definition::Static(_)
+                | Definition::Trait(_)
+                | Definition::TypeAlias(_)),
+                _,
+            ) => Some(def),
+            _ => None,
+        })
+        .collect()
 }
 
-fn find_names_to_import(
-    ctx: &AssistContext<'_>,
-    refs_in_target: Refs,
-    imported_defs: Vec<Definition>,
-) -> Vec<Name> {
-    let used_refs = refs_in_target.used_refs(ctx).filter_out_by_defs(imported_defs);
-    used_refs.0.iter().map(|r| r.visible_name.clone()).collect()
+fn find_names_to_import(refs_in_target: Refs, imported_defs: Vec<Definition>) -> Vec<Name> {
+    let final_refs = refs_in_target.filter_out_by_defs(imported_defs);
+    final_refs.0.iter().map(|r| r.visible_name.clone()).collect()
 }
 
 #[cfg(test)]
@@ -1036,4 +1138,83 @@ mod abc {
 }"#,
         )
     }
+
+    #[test]
+    fn expanding_glob_reexport() {
+        check_assist(
+            expand_glob_reexport,
+            r"
+mod foo {
+    pub struct Bar;
+    pub struct Baz;
+    struct Qux;
+
+    pub fn f() {}
+
+    pub(crate) fn g() {}
+    pub(self) fn h() {}
+}
+
+pub use foo::*$0;
+",
+            r"
+mod foo {
+    pub struct Bar;
+    pub struct Baz;
+    struct Qux;
+
+    pub fn f() {}
+
+    pub(crate) fn g() {}
+    pub(self) fn h() {}
+}
+
+pub use foo::{Bar, Baz, f};
+",
+        )
+    }
+
+    #[test]
+    fn expanding_recursive_glob_reexport() {
+        check_assist(
+            expand_glob_reexport,
+            r"
+mod foo {
+    pub use bar::*;
+    mod bar {
+        pub struct Bar;
+        pub struct Baz;
+    }
+}
+
+pub use foo::*$0;
+",
+            r"
+mod foo {
+    pub use bar::*;
+    mod bar {
+        pub struct Bar;
+        pub struct Baz;
+    }
+}
+
+pub use foo::{Bar, Baz};
+",
+        )
+    }
+
+    #[test]
+    fn expanding_reexport_is_not_applicable_for_private_import() {
+        check_assist_not_applicable(
+            expand_glob_reexport,
+            r"
+mod foo {
+    pub struct Bar;
+    pub struct Baz;
+}
+
+use foo::*$0;
+",
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 5c95b25f28d..179742f91b4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -270,6 +270,7 @@ mod handlers {
             destructure_tuple_binding::destructure_tuple_binding,
             destructure_struct_binding::destructure_struct_binding,
             expand_glob_import::expand_glob_import,
+            expand_glob_import::expand_glob_reexport,
             explicit_enum_discriminant::explicit_enum_discriminant,
             extract_expressions_from_format_string::extract_expressions_from_format_string,
             extract_struct_from_enum_variant::extract_struct_from_enum_variant,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 4b0fa704a22..0662527a387 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -910,6 +910,29 @@ fn qux(bar: Bar, baz: Baz) {}
 }
 
 #[test]
+fn doctest_expand_glob_reexport() {
+    check_doc_test(
+        "expand_glob_reexport",
+        r#####"
+mod foo {
+    pub struct Bar;
+    pub struct Baz;
+}
+
+pub use foo::*$0;
+"#####,
+        r#####"
+mod foo {
+    pub struct Bar;
+    pub struct Baz;
+}
+
+pub use foo::{Bar, Baz};
+"#####,
+    )
+}
+
+#[test]
 fn doctest_explicit_enum_discriminant() {
     check_doc_test(
         "explicit_enum_discriminant",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 2c39a8fdfed..28e2853096e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -2,17 +2,18 @@
 
 mod format_like;
 
-use hir::ItemInNs;
-use ide_db::text_edit::TextEdit;
+use base_db::SourceDatabase;
+use hir::{ItemInNs, Semantics};
 use ide_db::{
     documentation::{Documentation, HasDocs},
     imports::insert_use::ImportScope,
+    text_edit::TextEdit,
     ty_filter::TryEnum,
-    SnippetCap,
+    RootDatabase, SnippetCap,
 };
 use stdx::never;
 use syntax::{
-    ast::{self, make, AstNode, AstToken},
+    ast::{self, AstNode, AstToken},
     SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR},
     TextRange, TextSize,
 };
@@ -48,7 +49,8 @@ pub(crate) fn complete_postfix(
     };
     let expr_ctx = &dot_access.ctx;
 
-    let receiver_text = get_receiver_text(dot_receiver, receiver_is_ambiguous_float_literal);
+    let receiver_text =
+        get_receiver_text(&ctx.sema, dot_receiver, receiver_is_ambiguous_float_literal);
 
     let cap = match ctx.config.snippet_cap {
         Some(it) => it,
@@ -172,13 +174,15 @@ pub(crate) fn complete_postfix(
     // The rest of the postfix completions create an expression that moves an argument,
     // so it's better to consider references now to avoid breaking the compilation
 
-    let (dot_receiver, node_to_replace_with) = include_references(dot_receiver);
-    let receiver_text =
-        get_receiver_text(&node_to_replace_with, receiver_is_ambiguous_float_literal);
-    let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, &dot_receiver) {
-        Some(it) => it,
-        None => return,
-    };
+    let (dot_receiver_including_refs, prefix) = include_references(dot_receiver);
+    let mut receiver_text =
+        get_receiver_text(&ctx.sema, dot_receiver, receiver_is_ambiguous_float_literal);
+    receiver_text.insert_str(0, &prefix);
+    let postfix_snippet =
+        match build_postfix_snippet_builder(ctx, cap, &dot_receiver_including_refs) {
+            Some(it) => it,
+            None => return,
+        };
 
     if !ctx.config.snippets.is_empty() {
         add_custom_postfix_completions(acc, ctx, &postfix_snippet, &receiver_text);
@@ -222,7 +226,7 @@ pub(crate) fn complete_postfix(
     postfix_snippet("call", "function(expr)", &format!("${{1}}({receiver_text})"))
         .add_to(acc, ctx.db);
 
-    if let Some(parent) = dot_receiver.syntax().parent().and_then(|p| p.parent()) {
+    if let Some(parent) = dot_receiver_including_refs.syntax().parent().and_then(|p| p.parent()) {
         if matches!(parent.kind(), STMT_LIST | EXPR_STMT) {
             postfix_snippet("let", "let", &format!("let $0 = {receiver_text};"))
                 .add_to(acc, ctx.db);
@@ -231,9 +235,9 @@ pub(crate) fn complete_postfix(
         }
     }
 
-    if let ast::Expr::Literal(literal) = dot_receiver.clone() {
+    if let ast::Expr::Literal(literal) = dot_receiver_including_refs.clone() {
         if let Some(literal_text) = ast::String::cast(literal.token()) {
-            add_format_like_completions(acc, ctx, &dot_receiver, cap, &literal_text);
+            add_format_like_completions(acc, ctx, &dot_receiver_including_refs, cap, &literal_text);
         }
     }
 
@@ -260,14 +264,20 @@ pub(crate) fn complete_postfix(
     }
 }
 
-fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String {
-    let mut text = if receiver_is_ambiguous_float_literal {
-        let text = receiver.syntax().text();
-        let without_dot = ..text.len() - TextSize::of('.');
-        text.slice(without_dot).to_string()
-    } else {
-        receiver.to_string()
+fn get_receiver_text(
+    sema: &Semantics<'_, RootDatabase>,
+    receiver: &ast::Expr,
+    receiver_is_ambiguous_float_literal: bool,
+) -> String {
+    // Do not just call `receiver.to_string()`, as that will mess up whitespaces inside macros.
+    let Some(mut range) = sema.original_range_opt(receiver.syntax()) else {
+        return receiver.to_string();
     };
+    if receiver_is_ambiguous_float_literal {
+        range.range = TextRange::at(range.range.start(), range.range.len() - TextSize::of('.'))
+    }
+    let file_text = sema.db.file_text(range.file_id.file_id());
+    let mut text = file_text[range.range].to_owned();
 
     // The receiver texts should be interpreted as-is, as they are expected to be
     // normal Rust expressions.
@@ -284,7 +294,7 @@ fn escape_snippet_bits(text: &mut String) {
     stdx::replace(text, '$', "\\$");
 }
 
-fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) {
+fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
     let mut resulting_element = initial_element.clone();
 
     while let Some(field_expr) = resulting_element.syntax().parent().and_then(ast::FieldExpr::cast)
@@ -292,7 +302,7 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) {
         resulting_element = ast::Expr::from(field_expr);
     }
 
-    let mut new_element_opt = initial_element.clone();
+    let mut prefix = String::new();
 
     while let Some(parent_deref_element) =
         resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
@@ -303,7 +313,7 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) {
 
         resulting_element = ast::Expr::from(parent_deref_element);
 
-        new_element_opt = make::expr_prefix(syntax::T![*], new_element_opt).into();
+        prefix.insert(0, '*');
     }
 
     if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) {
@@ -317,7 +327,7 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) {
             let exclusive = parent_ref_element.mut_token().is_some();
             resulting_element = ast::Expr::from(parent_ref_element);
 
-            new_element_opt = make::expr_ref(new_element_opt, exclusive);
+            prefix.insert_str(0, if exclusive { "&mut " } else { "&" });
         }
     } else {
         // If we do not find any ref expressions, restore
@@ -325,7 +335,7 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) {
         resulting_element = initial_element.clone();
     }
 
-    (resulting_element, new_element_opt)
+    (resulting_element, prefix)
 }
 
 fn build_postfix_snippet_builder<'ctx>(
@@ -901,4 +911,31 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn inside_macro() {
+        check_edit(
+            "box",
+            r#"
+macro_rules! assert {
+    ( $it:expr $(,)? ) => { $it };
+}
+
+fn foo() {
+    let a = true;
+    assert!(if a == false { true } else { false }.$0);
+}
+        "#,
+            r#"
+macro_rules! assert {
+    ( $it:expr $(,)? ) => { $it };
+}
+
+fn foo() {
+    let a = true;
+    assert!(Box::new(if a == false { true } else { false }));
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index bad53608056..6f71c3d9bd7 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -108,7 +108,7 @@ impl Definition {
                 ItemContainer::Trait(it) => Some(it.into()),
                 ItemContainer::Impl(it) => Some(it.into()),
                 ItemContainer::Module(it) => Some(it.into()),
-                ItemContainer::ExternBlock() | ItemContainer::Crate(_) => None,
+                ItemContainer::ExternBlock(_) | ItemContainer::Crate(_) => None,
             }
         }
         match self {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
index 14af22c3193..ed9d6c67501 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
@@ -9107,8 +9107,8 @@ The tracking issue for this feature is: [#27721]
         deny_since: None,
     },
     Lint {
-        label: "pattern_complexity",
-        description: r##"# `pattern_complexity`
+        label: "pattern_complexity_limit",
+        description: r##"# `pattern_complexity_limit`
 
 This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 7126617cdee..0520bb3fe9b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -40,7 +40,7 @@ pub(crate) fn mismatched_arg_count(
     Diagnostic::new(
         DiagnosticCode::RustcHardError("E0107"),
         message,
-        invalid_args_range(ctx, d.call_expr.map(AstPtr::wrap_left), d.expected, d.found),
+        invalid_args_range(ctx, d.call_expr, d.expected, d.found),
     )
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs
new file mode 100644
index 00000000000..ccf51723418
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs
@@ -0,0 +1,59 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: parenthesized-generic-args-without-fn-trait
+//
+// This diagnostic is shown when a `Fn`-trait-style generic parameters (`Trait(A, B) -> C`)
+// was used on non-`Fn` trait/type.
+pub(crate) fn parenthesized_generic_args_without_fn_trait(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::ParenthesizedGenericArgsWithoutFnTrait,
+) -> Diagnostic {
+    Diagnostic::new_with_syntax_node_ptr(
+        ctx,
+        DiagnosticCode::RustcHardError("E0214"),
+        "parenthesized type parameters may only be used with a `Fn` trait",
+        d.args.map(Into::into),
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::check_diagnostics;
+
+    #[test]
+    fn fn_traits_work() {
+        check_diagnostics(
+            r#"
+//- minicore: async_fn, fn
+fn foo<
+    A: Fn(),
+    B: FnMut() -> i32,
+    C: FnOnce(&str, bool),
+    D: AsyncFn::(u32) -> u32,
+    E: AsyncFnMut(),
+    F: AsyncFnOnce() -> bool,
+>() {}
+        "#,
+        );
+    }
+
+    #[test]
+    fn non_fn_trait() {
+        check_diagnostics(
+            r#"
+struct Struct<T>(T);
+enum Enum<T> { EnumVariant(T) }
+type TypeAlias<T> = bool;
+
+type Foo = TypeAlias() -> bool;
+                 // ^^ error: parenthesized type parameters may only be used with a `Fn` trait
+
+fn foo(_a: Struct(i32)) {
+              // ^^^^^ error: parenthesized type parameters may only be used with a `Fn` trait
+    let _ = <Enum::(u32)>::EnumVariant(0);
+              // ^^^^^^^ error: parenthesized type parameters may only be used with a `Fn` trait
+}
+        "#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 73dcbc13b79..7cf8282d052 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1235,4 +1235,25 @@ fn f() {
 "#,
         );
     }
+
+    #[test]
+    fn complex_enum_variant_non_ref_pat() {
+        check_diagnostics(
+            r#"
+enum Enum { Variant }
+
+trait Trait {
+    type Assoc;
+}
+impl Trait for () {
+    type Assoc = Enum;
+}
+
+fn foo(v: &Enum) {
+    let <Enum>::Variant = v;
+    let <() as Trait>::Assoc::Variant = v;
+}
+    "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 4accd181ca4..dfb03eee732 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -1,5 +1,6 @@
 use std::iter;
 
+use either::Either;
 use hir::{db::ExpandDatabase, Adt, FileRange, HasSource, HirDisplay, InFile, Struct, Union};
 use ide_db::text_edit::TextEdit;
 use ide_db::{
@@ -41,7 +42,7 @@ pub(crate) fn unresolved_field(
         ),
         adjusted_display_range(ctx, d.expr, &|expr| {
             Some(
-                match expr {
+                match expr.left()? {
                     ast::Expr::MethodCallExpr(it) => it.name_ref(),
                     ast::Expr::FieldExpr(it) => it.name_ref(),
                     _ => None,
@@ -72,7 +73,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<A
 fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Assist> {
     // Get the FileRange of the invalid field access
     let root = ctx.sema.db.parse_or_expand(d.expr.file_id);
-    let expr = d.expr.value.to_node(&root);
+    let expr = d.expr.value.to_node(&root).left()?;
 
     let error_range = ctx.sema.original_range_opt(expr.syntax())?;
     let field_name = d.name.as_str();
@@ -263,7 +264,7 @@ fn record_field_layout(
 // FIXME: We should fill out the call here, move the cursor and trigger signature help
 fn method_fix(
     ctx: &DiagnosticsContext<'_>,
-    expr_ptr: &InFile<AstPtr<ast::Expr>>,
+    expr_ptr: &InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
 ) -> Option<Assist> {
     let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
     let expr = expr_ptr.value.to_node(&root);
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 4ab649cc162..e4de107249b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -1,4 +1,4 @@
-use hir::{db::ExpandDatabase, AssocItem, FileRange, HirDisplay, InFile};
+use hir::{db::ExpandDatabase, FileRange, HirDisplay, InFile};
 use ide_db::text_edit::TextEdit;
 use ide_db::{
     assists::{Assist, AssistId, AssistKind},
@@ -35,7 +35,7 @@ pub(crate) fn unresolved_method(
         ),
         adjusted_display_range(ctx, d.expr, &|expr| {
             Some(
-                match expr {
+                match expr.left()? {
                     ast::Expr::MethodCallExpr(it) => it.name_ref(),
                     ast::Expr::FieldExpr(it) => it.name_ref(),
                     _ => None,
@@ -85,7 +85,7 @@ fn field_fix(
     let expr_ptr = &d.expr;
     let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
     let expr = expr_ptr.value.to_node(&root);
-    let (file_id, range) = match expr {
+    let (file_id, range) = match expr.left()? {
         ast::Expr::MethodCallExpr(mcall) => {
             let FileRange { range, file_id } =
                 ctx.sema.original_range_opt(mcall.receiver()?.syntax())?;
@@ -112,12 +112,12 @@ fn field_fix(
 }
 
 fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option<Assist> {
-    if let Some(assoc_item_id) = d.assoc_func_with_same_name {
+    if let Some(f) = d.assoc_func_with_same_name {
         let db = ctx.sema.db;
 
         let expr_ptr = &d.expr;
         let root = db.parse_or_expand(expr_ptr.file_id);
-        let expr: ast::Expr = expr_ptr.value.to_node(&root);
+        let expr: ast::Expr = expr_ptr.value.to_node(&root).left()?;
 
         let call = ast::MethodCallExpr::cast(expr.syntax().clone())?;
         let range = InFile::new(expr_ptr.file_id, call.syntax().text_range())
@@ -127,30 +127,25 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -
         let receiver = call.receiver()?;
         let receiver_type = &ctx.sema.type_of_expr(&receiver)?.original;
 
-        let need_to_take_receiver_as_first_arg = match hir::AssocItem::from(assoc_item_id) {
-            AssocItem::Function(f) => {
-                let assoc_fn_params = f.assoc_fn_params(db);
-                if assoc_fn_params.is_empty() {
-                    false
-                } else {
-                    assoc_fn_params
-                        .first()
-                        .map(|first_arg| {
-                            // For generic type, say `Box`, take `Box::into_raw(b: Self)` as example,
-                            // type of `b` is `Self`, which is `Box<T, A>`, containing unspecified generics.
-                            // However, type of `receiver` is specified, it could be `Box<i32, Global>` or something like that,
-                            // so `first_arg.ty() == receiver_type` evaluate to `false` here.
-                            // Here add `first_arg.ty().as_adt() == receiver_type.as_adt()` as guard,
-                            // apply `.as_adt()` over `Box<T, A>` or `Box<i32, Global>` gets `Box`, so we get `true` here.
-
-                            // FIXME: it fails when type of `b` is `Box` with other generic param different from `receiver`
-                            first_arg.ty() == receiver_type
-                                || first_arg.ty().as_adt() == receiver_type.as_adt()
-                        })
-                        .unwrap_or(false)
-                }
-            }
-            _ => false,
+        let assoc_fn_params = f.assoc_fn_params(db);
+        let need_to_take_receiver_as_first_arg = if assoc_fn_params.is_empty() {
+            false
+        } else {
+            assoc_fn_params
+                .first()
+                .map(|first_arg| {
+                    // For generic type, say `Box`, take `Box::into_raw(b: Self)` as example,
+                    // type of `b` is `Self`, which is `Box<T, A>`, containing unspecified generics.
+                    // However, type of `receiver` is specified, it could be `Box<i32, Global>` or something like that,
+                    // so `first_arg.ty() == receiver_type` evaluate to `false` here.
+                    // Here add `first_arg.ty().as_adt() == receiver_type.as_adt()` as guard,
+                    // apply `.as_adt()` over `Box<T, A>` or `Box<i32, Global>` gets `Box`, so we get `true` here.
+
+                    // FIXME: it fails when type of `b` is `Box` with other generic param different from `receiver`
+                    first_arg.ty() == receiver_type
+                        || first_arg.ty().as_adt() == receiver_type.as_adt()
+                })
+                .unwrap_or(false)
         };
 
         let mut receiver_type_adt_name =
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
index 67ece566941..d5caf4de336 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -263,4 +263,17 @@ fn main() {
 "#,
         );
     }
+
+    // regression test as we used to panic in this scenario
+    #[test]
+    fn unknown_struct_pattern_param_type() {
+        check_diagnostics(
+            r#"
+struct S { field : u32 }
+fn f(S { field }: error) {
+      // ^^^^^ 💡 warn: unused variable
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 50c91a69602..3ea41aa7e85 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -43,6 +43,7 @@ mod handlers {
     pub(crate) mod mutability_errors;
     pub(crate) mod no_such_field;
     pub(crate) mod non_exhaustive_let;
+    pub(crate) mod parenthesized_generic_args_without_fn_trait;
     pub(crate) mod private_assoc_item;
     pub(crate) mod private_field;
     pub(crate) mod remove_trailing_return;
@@ -466,7 +467,12 @@ pub fn semantic_diagnostics(
                 Some(it) => it,
                 None => continue,
             },
-            AnyDiagnostic::GenericArgsProhibited(d) => handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d)
+            AnyDiagnostic::GenericArgsProhibited(d) => {
+                handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d)
+            }
+            AnyDiagnostic::ParenthesizedGenericArgsWithoutFnTrait(d) => {
+                handlers::parenthesized_generic_args_without_fn_trait::parenthesized_generic_args_without_fn_trait(&ctx, &d)
+            }
         };
         res.push(d)
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
index 006e6e8246e..e47891bbdfe 100644
--- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
@@ -1,6 +1,6 @@
 use hir::{HasSource, InFile, InRealFile, Semantics};
 use ide_db::{
-    defs::Definition, helpers::visit_file_defs, FileId, FilePosition, FileRange, FxHashSet,
+    defs::Definition, helpers::visit_file_defs, FileId, FilePosition, FileRange, FxIndexSet,
     RootDatabase,
 };
 use itertools::Itertools;
@@ -55,7 +55,7 @@ pub(crate) fn annotations(
     config: &AnnotationConfig,
     file_id: FileId,
 ) -> Vec<Annotation> {
-    let mut annotations = FxHashSet::default();
+    let mut annotations = FxIndexSet::default();
 
     if config.annotate_runnables {
         for runnable in runnables(db, file_id) {
@@ -170,7 +170,12 @@ pub(crate) fn annotations(
         }));
     }
 
-    annotations.into_iter().sorted_by_key(|a| (a.range.start(), a.range.end())).collect()
+    annotations
+        .into_iter()
+        .sorted_by_key(|a| {
+            (a.range.start(), a.range.end(), matches!(a.kind, AnnotationKind::Runnable(..)))
+        })
+        .collect()
 }
 
 pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
@@ -537,6 +542,20 @@ fn main() {
                     },
                     Annotation {
                         range: 69..73,
+                        kind: HasReferences {
+                            pos: FilePositionWrapper {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 69,
+                            },
+                            data: Some(
+                                [],
+                            ),
+                        },
+                    },
+                    Annotation {
+                        range: 69..73,
                         kind: Runnable(
                             Runnable {
                                 use_name_in_title: false,
@@ -559,20 +578,6 @@ fn main() {
                             },
                         ),
                     },
-                    Annotation {
-                        range: 69..73,
-                        kind: HasReferences {
-                            pos: FilePositionWrapper {
-                                file_id: FileId(
-                                    0,
-                                ),
-                                offset: 69,
-                            },
-                            data: Some(
-                                [],
-                            ),
-                        },
-                    },
                 ]
             "#]],
         );
@@ -719,6 +724,20 @@ fn main() {
                     },
                     Annotation {
                         range: 61..65,
+                        kind: HasReferences {
+                            pos: FilePositionWrapper {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 61,
+                            },
+                            data: Some(
+                                [],
+                            ),
+                        },
+                    },
+                    Annotation {
+                        range: 61..65,
                         kind: Runnable(
                             Runnable {
                                 use_name_in_title: false,
@@ -741,20 +760,6 @@ fn main() {
                             },
                         ),
                     },
-                    Annotation {
-                        range: 61..65,
-                        kind: HasReferences {
-                            pos: FilePositionWrapper {
-                                file_id: FileId(
-                                    0,
-                                ),
-                                offset: 61,
-                            },
-                            data: Some(
-                                [],
-                            ),
-                        },
-                    },
                 ]
             "#]],
         );
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 bdafb701ff5..60a904233a9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -3290,4 +3290,38 @@ fn main() {
     "#,
         );
     }
+
+    #[test]
+    fn shadow_builtin_type_by_module() {
+        check(
+            r#"
+mod Foo{
+pub mod str {
+     // ^^^
+    pub fn foo() {}
+}
+}
+
+fn main() {
+    use Foo::str;
+    let s = st$0r::foo();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn not_goto_module_because_str_is_builtin_type() {
+        check(
+            r#"
+mod str {
+pub fn foo() {}
+}
+
+fn main() {
+    let s = st$0r::f();
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
index 2bc91b68ed8..652dff0bc56 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
@@ -7,7 +7,7 @@ use crate::{InlayHint, InlayHintsConfig};
 
 pub(super) fn extern_block_hints(
     acc: &mut Vec<InlayHint>,
-    FamousDefs(_sema, _): &FamousDefs<'_, '_>,
+    FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
     _file_id: EditionedFileId,
     extern_block: ast::ExternBlock,
@@ -16,6 +16,7 @@ pub(super) fn extern_block_hints(
         return None;
     }
     let abi = extern_block.abi()?;
+    sema.to_def(&extern_block)?;
     acc.push(InlayHint {
         range: abi.syntax().text_range(),
         position: crate::InlayHintPosition::Before,
@@ -33,7 +34,7 @@ pub(super) fn extern_block_hints(
 
 pub(super) fn fn_hints(
     acc: &mut Vec<InlayHint>,
-    FamousDefs(_sema, _): &FamousDefs<'_, '_>,
+    FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
     _file_id: EditionedFileId,
     fn_: &ast::Fn,
@@ -43,14 +44,16 @@ pub(super) fn fn_hints(
     if !implicit_unsafe {
         return None;
     }
-    let fn_ = fn_.fn_token()?;
-    acc.push(item_hint(config, extern_block, fn_));
+    let fn_token = fn_.fn_token()?;
+    if sema.to_def(fn_).is_some_and(|def| def.extern_block(sema.db).is_some()) {
+        acc.push(item_hint(config, extern_block, fn_token));
+    }
     Some(())
 }
 
 pub(super) fn static_hints(
     acc: &mut Vec<InlayHint>,
-    FamousDefs(_sema, _): &FamousDefs<'_, '_>,
+    FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
     _file_id: EditionedFileId,
     static_: &ast::Static,
@@ -60,8 +63,10 @@ pub(super) fn static_hints(
     if !implicit_unsafe {
         return None;
     }
-    let static_ = static_.static_token()?;
-    acc.push(item_hint(config, extern_block, static_));
+    let static_token = static_.static_token()?;
+    if sema.to_def(static_).is_some_and(|def| def.extern_block(sema.db).is_some()) {
+        acc.push(item_hint(config, extern_block, static_token));
+    }
     Some(())
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
index 27c7c3d4981..390139d214e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -54,7 +54,8 @@ pub(super) fn hints(
             };
             let range = match terminator.span {
                 MirSpan::ExprId(e) => match source_map.expr_syntax(e) {
-                    Ok(s) => {
+                    // don't show inlay hint for macro
+                    Ok(s) if !s.file_id.is_macro() => {
                         let root = &s.file_syntax(sema.db);
                         let expr = s.value.to_node(root);
                         let expr = expr.syntax();
@@ -69,11 +70,11 @@ pub(super) fn hints(
                             }
                         }
                     }
-                    Err(_) => continue,
+                    _ => continue,
                 },
                 MirSpan::PatId(p) => match source_map.pat_syntax(p) {
-                    Ok(s) => s.value.text_range(),
-                    Err(_) => continue,
+                    Ok(s) if !s.file_id.is_macro() => s.value.text_range(),
+                    _ => continue,
                 },
                 MirSpan::BindingId(b) => {
                     match source_map
@@ -81,13 +82,13 @@ pub(super) fn hints(
                         .iter()
                         .find_map(|p| source_map.pat_syntax(*p).ok())
                     {
-                        Some(s) => s.value.text_range(),
-                        None => continue,
+                        Some(s) if !s.file_id.is_macro() => s.value.text_range(),
+                        _ => continue,
                     }
                 }
                 MirSpan::SelfParam => match source_map.self_param_syntax() {
-                    Some(s) => s.value.text_range(),
-                    None => continue,
+                    Some(s) if !s.file_id.is_macro() => s.value.text_range(),
+                    _ => continue,
                 },
                 MirSpan::Unknown => continue,
             };
@@ -231,4 +232,25 @@ mod tests {
 "#,
         );
     }
+
+    #[test]
+    fn ignore_inlay_hint_for_macro_call() {
+        check_with_config(
+            ONLY_DROP_CONFIG,
+            r#"
+    struct X;
+
+    macro_rules! my_macro {
+        () => {{
+            let bbb = X;
+            bbb
+        }};
+    }
+
+    fn test() -> X {
+        my_macro!()
+    }
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index 78c9f2309a0..509ae3204c3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -4,8 +4,8 @@ use arrayvec::ArrayVec;
 use ast::HasName;
 use cfg::{CfgAtom, CfgExpr};
 use hir::{
-    db::HirDatabase, sym, AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate, HasSource, HirFileIdExt,
-    ModPath, Name, PathKind, Semantics, Symbol,
+    db::HirDatabase, sym, symbols::FxIndexSet, AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate,
+    HasSource, HirFileIdExt, ModPath, Name, PathKind, Semantics, Symbol,
 };
 use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
 use ide_db::{
@@ -13,7 +13,7 @@ use ide_db::{
     documentation::docs_from_attrs,
     helpers::visit_file_defs,
     search::{FileReferenceNode, SearchScope},
-    FilePosition, FxHashMap, FxHashSet, RootDatabase, SymbolKind,
+    FilePosition, FxHashMap, FxIndexMap, RootDatabase, SymbolKind,
 };
 use itertools::Itertools;
 use smallvec::SmallVec;
@@ -61,8 +61,8 @@ pub enum RunnableKind {
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
 enum RunnableDiscKind {
-    Test,
     TestMod,
+    Test,
     DocTest,
     Bench,
     Bin,
@@ -130,7 +130,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
     let mut res = Vec::new();
     // Record all runnables that come from macro expansions here instead.
     // In case an expansion creates multiple runnables we want to name them to avoid emitting a bunch of equally named runnables.
-    let mut in_macro_expansion = FxHashMap::<hir::HirFileId, Vec<Runnable>>::default();
+    let mut in_macro_expansion = FxIndexMap::<hir::HirFileId, Vec<Runnable>>::default();
     let mut add_opt = |runnable: Option<Runnable>, def| {
         if let Some(runnable) = runnable.filter(|runnable| runnable.nav.file_id == file_id) {
             if let Some(def) = def {
@@ -182,20 +182,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
             r
         })
     }));
-    res.sort_by(|Runnable { nav, kind, .. }, Runnable { nav: nav_b, kind: kind_b, .. }| {
-        // full_range.start < focus_range.start < name, should give us a decent unique ordering
-        nav.full_range
-            .start()
-            .cmp(&nav_b.full_range.start())
-            .then_with(|| {
-                let t_0 = || TextSize::from(0);
-                nav.focus_range
-                    .map_or_else(t_0, |it| it.start())
-                    .cmp(&nav_b.focus_range.map_or_else(t_0, |it| it.start()))
-            })
-            .then_with(|| kind.disc().cmp(&kind_b.disc()))
-            .then_with(|| nav.name.cmp(&nav_b.name))
-    });
+    res.sort_by(cmp_runnables);
     res
 }
 
@@ -215,12 +202,30 @@ pub(crate) fn related_tests(
     search_scope: Option<SearchScope>,
 ) -> Vec<Runnable> {
     let sema = Semantics::new(db);
-    let mut res: FxHashSet<Runnable> = FxHashSet::default();
+    let mut res: FxIndexSet<Runnable> = FxIndexSet::default();
     let syntax = sema.parse_guess_edition(position.file_id).syntax().clone();
 
     find_related_tests(&sema, &syntax, position, search_scope, &mut res);
 
-    res.into_iter().collect()
+    res.into_iter().sorted_by(cmp_runnables).collect()
+}
+
+fn cmp_runnables(
+    Runnable { nav, kind, .. }: &Runnable,
+    Runnable { nav: nav_b, kind: kind_b, .. }: &Runnable,
+) -> std::cmp::Ordering {
+    // full_range.start < focus_range.start < name, should give us a decent unique ordering
+    nav.full_range
+        .start()
+        .cmp(&nav_b.full_range.start())
+        .then_with(|| {
+            let t_0 = || TextSize::from(0);
+            nav.focus_range
+                .map_or_else(t_0, |it| it.start())
+                .cmp(&nav_b.focus_range.map_or_else(t_0, |it| it.start()))
+        })
+        .then_with(|| kind.disc().cmp(&kind_b.disc()))
+        .then_with(|| nav.name.cmp(&nav_b.name))
 }
 
 fn find_related_tests(
@@ -228,7 +233,7 @@ fn find_related_tests(
     syntax: &SyntaxNode,
     position: FilePosition,
     search_scope: Option<SearchScope>,
-    tests: &mut FxHashSet<Runnable>,
+    tests: &mut FxIndexSet<Runnable>,
 ) {
     // FIXME: why is this using references::find_defs, this should use ide_db::search
     let defs = match references::find_defs(sema, syntax, position.offset) {
@@ -268,7 +273,7 @@ fn find_related_tests_in_module(
     syntax: &SyntaxNode,
     fn_def: &ast::Fn,
     parent_module: &hir::Module,
-    tests: &mut FxHashSet<Runnable>,
+    tests: &mut FxIndexSet<Runnable>,
 ) {
     let fn_name = match fn_def.name() {
         Some(it) => it,
@@ -1228,8 +1233,8 @@ gen_main!();
                     "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..315, name: \"\", kind: Module })",
                     "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 267..292, focus_range: 271..276, name: \"tests\", kind: Module, description: \"mod tests\" })",
                     "(Test, NavigationTarget { file_id: FileId(0), full_range: 283..290, name: \"foo_test\", kind: Function })",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 293..301, name: \"foo_test2\", kind: Function }, true)",
                     "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 293..301, name: \"tests2\", kind: Module, description: \"mod tests2\" }, true)",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 293..301, name: \"foo_test2\", kind: Function }, true)",
                     "(Bin, NavigationTarget { file_id: FileId(0), full_range: 302..314, name: \"main\", kind: Function })",
                 ]
             "#]],
@@ -1258,10 +1263,10 @@ foo!();
 "#,
             expect![[r#"
                 [
+                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo_tests\", kind: Module, description: \"mod foo_tests\" }, true)",
                     "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo0\", kind: Function }, true)",
                     "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo1\", kind: Function }, true)",
                     "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo2\", kind: Function }, true)",
-                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo_tests\", kind: Module, description: \"mod foo_tests\" }, true)",
                 ]
             "#]],
         );
@@ -1501,18 +1506,18 @@ mod tests {
                         file_id: FileId(
                             0,
                         ),
-                        full_range: 121..185,
-                        focus_range: 136..145,
-                        name: "foo2_test",
+                        full_range: 52..115,
+                        focus_range: 67..75,
+                        name: "foo_test",
                         kind: Function,
                     },
                     NavigationTarget {
                         file_id: FileId(
                             0,
                         ),
-                        full_range: 52..115,
-                        focus_range: 67..75,
-                        name: "foo_test",
+                        full_range: 121..185,
+                        focus_range: 136..145,
+                        name: "foo2_test",
                         kind: Function,
                     },
                 ]
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
index 479c0b381a4..194fde11601 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
@@ -703,6 +703,7 @@ fn highlight_name_ref_by_syntax(
     };
 
     match parent.kind() {
+        EXTERN_CRATE => HlTag::Symbol(SymbolKind::Module) | HlMod::CrateRoot,
         METHOD_CALL_EXPR => ast::MethodCallExpr::cast(parent)
             .and_then(|it| highlight_method_call(sema, krate, &it, edition))
             .unwrap_or_else(|| SymbolKind::Method.into()),
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 5ff96ae2a74..eb77c14c2a5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -50,6 +50,15 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">test</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span>
 <span class="comment documentation">//! ```</span>
 
+<span class="comment documentation">//! ```rust</span>
+<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="self_keyword crate_root injected">self</span><span class="semicolon injected">;</span>
+<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">std</span><span class="semicolon injected">;</span>
+<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">core</span><span class="semicolon injected">;</span>
+<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">alloc</span><span class="semicolon injected">;</span>
+<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">proc_macro</span><span class="semicolon injected">;</span>
+<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">test</span><span class="semicolon injected">;</span>
+<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">Krate</span><span class="semicolon injected">;</span>
+<span class="comment documentation">//! ```</span>
 <span class="keyword">mod</span> <span class="module declaration">outline_module</span><span class="semicolon">;</span>
 
 <span class="comment documentation">/// ```</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index 9be7c92fc79..9477d0d1b87 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -48,17 +48,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span>
 <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
 
-<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration public">ops</span> <span class="brace">{</span>
-    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_once"</span><span class="attribute_bracket attribute">]</span>
-    <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">FnOnce</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
-
-    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_mut"</span><span class="attribute_bracket attribute">]</span>
-    <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">FnMut</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait public">FnOnce</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
-
-    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn"</span><span class="attribute_bracket attribute">]</span>
-    <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">Fn</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait public">FnMut</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="brace">}</span>
-
 <span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="brace">{</span>
     <span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
 <span class="brace">}</span>
@@ -125,8 +114,8 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="const_param const">FOO</span>
 <span class="brace">}</span>
 
-<span class="keyword">use</span> <span class="module public">ops</span><span class="operator">::</span><span class="trait public">Fn</span><span class="semicolon">;</span>
-<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="angle">&lt;</span><span class="type_param declaration">F</span><span class="colon">:</span> <span class="trait public">Fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="value_param callable declaration">f</span><span class="colon">:</span> <span class="type_param">F</span><span class="parenthesis">)</span> <span class="brace">{</span>
+<span class="keyword">use</span> <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">ops</span><span class="operator">::</span><span class="trait default_library library">Fn</span><span class="semicolon">;</span>
+<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="angle">&lt;</span><span class="type_param declaration">F</span><span class="colon">:</span> <span class="trait default_library library">Fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="value_param callable declaration">f</span><span class="colon">:</span> <span class="type_param">F</span><span class="parenthesis">)</span> <span class="brace">{</span>
     <span class="value_param callable">f</span><span class="parenthesis">(</span><span class="parenthesis">)</span>
 <span class="brace">}</span>
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index b9520ae2bba..3775265f234 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -136,22 +136,11 @@ use self::foo as bar;
 fn test_highlighting() {
     check_highlighting(
         r#"
-//- minicore: derive, copy
+//- minicore: derive, copy, fn
 //- /main.rs crate:main deps:foo
 use inner::{self as inner_mod};
 mod inner {}
 
-pub mod ops {
-    #[lang = "fn_once"]
-    pub trait FnOnce<Args> {}
-
-    #[lang = "fn_mut"]
-    pub trait FnMut<Args>: FnOnce<Args> {}
-
-    #[lang = "fn"]
-    pub trait Fn<Args>: FnMut<Args> {}
-}
-
 struct Foo {
     x: u32,
 }
@@ -218,7 +207,7 @@ fn const_param<const FOO: usize>() -> usize {
     FOO
 }
 
-use ops::Fn;
+use core::ops::Fn;
 fn baz<F: Fn() -> ()>(f: F) {
     f()
 }
@@ -722,6 +711,15 @@ fn test_highlight_doc_comment() {
 //! fn test() {}
 //! ```
 
+//! ```rust
+//! extern crate self;
+//! extern crate std;
+//! extern crate core;
+//! extern crate alloc;
+//! extern crate proc_macro;
+//! extern crate test;
+//! extern crate Krate;
+//! ```
 mod outline_module;
 
 /// ```
@@ -1084,6 +1082,9 @@ pub struct Struct;
     );
 }
 
+// Rainbow highlighting uses a deterministic hash (fxhash) but the hashing does differ
+// depending on the pointer width so only runs this on 64-bit targets.
+#[cfg(target_pointer_width = "64")]
 #[test]
 fn test_rainbow_highlighting() {
     check_highlighting(
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 66553a2661a..be0de6c9366 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -13,15 +13,35 @@ use crate::{
 
 macro_rules! define_symbols {
     (@WITH_NAME: $($alias:ident = $value:literal,)* @PLAIN: $($name:ident,)*) => {
-        // Ideally we would be emitting `const` here, but then we no longer have stable addresses
-        // which is what we are relying on for equality! In the future if consts can refer to
-        // statics we should swap these for `const`s and have the string literal being pointed
-        // to be statics to refer to such that their address is stable.
+        // We define symbols as both `const`s and `static`s because some const code requires const symbols,
+        // but code from before the transition relies on the lifetime of the predefined symbols and making them
+        // `const`s make it error (because now they're temporaries). In the future we probably should only
+        // use consts.
+
+        /// Predefined symbols as `const`s (instead of the default `static`s).
+        pub mod consts {
+            use super::{Symbol, TaggedArcPtr};
+
+            // The strings should be in `static`s so that symbol equality holds.
+            $(
+                pub const $name: Symbol = {
+                    static SYMBOL_STR: &str = stringify!($name);
+                    Symbol { repr: TaggedArcPtr::non_arc(&SYMBOL_STR) }
+                };
+            )*
+            $(
+                pub const $alias: Symbol = {
+                    static SYMBOL_STR: &str = $value;
+                    Symbol { repr: TaggedArcPtr::non_arc(&SYMBOL_STR) }
+                };
+            )*
+        }
+
         $(
-            pub static $name: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&stringify!($name)) };
+            pub static $name: Symbol = consts::$name;
         )*
         $(
-            pub static $alias: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&$value) };
+            pub static $alias: Symbol = consts::$alias;
         )*
 
 
@@ -428,6 +448,7 @@ define_symbols! {
     rustc_layout_scalar_valid_range_start,
     rustc_legacy_const_generics,
     rustc_macro_transparency,
+    rustc_paren_sugar,
     rustc_reallocator,
     rustc_reservation_impl,
     rustc_safe_intrinsic,
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 5654c04a592..67ee9d11199 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -94,7 +94,9 @@ pub fn load_workspace(
             let contents = loader.load_sync(path);
             let path = vfs::VfsPath::from(path.to_path_buf());
             vfs.set_file_contents(path.clone(), contents);
-            vfs.file_id(&path)
+            vfs.file_id(&path).and_then(|(file_id, excluded)| {
+                (excluded == vfs::FileExcluded::No).then_some(file_id)
+            })
         },
         extra_env,
     );
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 e4a61134620..b5f4e43a115 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
@@ -277,6 +277,9 @@ impl CargoWorkspace {
     /// Fetches the metadata for the given `cargo_toml` manifest.
     /// A successful result may contain another metadata error if the initial fetching failed but
     /// the `--no-deps` retry succeeded.
+    ///
+    /// The sysroot is used to set the `RUSTUP_TOOLCHAIN` env var when invoking cargo
+    /// to ensure that the rustup proxy uses the correct toolchain.
     pub fn fetch_metadata(
         cargo_toml: &ManifestPath,
         current_dir: &AbsPath,
diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
index fc1fd7b877f..0c734474682 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -260,19 +260,19 @@ fn parse_cfg(s: &str) -> Result<cfg::CfgAtom, String> {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub enum SysrootSourceWorkspaceConfig {
+pub enum RustSourceWorkspaceConfig {
     CargoMetadata(CargoMetadataConfig),
     Stitched,
 }
 
-impl Default for SysrootSourceWorkspaceConfig {
+impl Default for RustSourceWorkspaceConfig {
     fn default() -> Self {
-        SysrootSourceWorkspaceConfig::default_cargo()
+        RustSourceWorkspaceConfig::default_cargo()
     }
 }
 
-impl SysrootSourceWorkspaceConfig {
+impl RustSourceWorkspaceConfig {
     pub fn default_cargo() -> Self {
-        SysrootSourceWorkspaceConfig::CargoMetadata(Default::default())
+        RustSourceWorkspaceConfig::CargoMetadata(Default::default())
     }
 }
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 8f633d24be9..544ba43ba66 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -22,38 +22,40 @@ use toolchain::{probe_for_binary, Tool};
 
 use crate::{
     cargo_workspace::CargoMetadataConfig, utf8_stdout, CargoWorkspace, ManifestPath,
-    SysrootSourceWorkspaceConfig,
+    RustSourceWorkspaceConfig,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Sysroot {
     root: Option<AbsPathBuf>,
-    src_root: Option<AbsPathBuf>,
-    workspace: SysrootWorkspace,
+    rust_lib_src_root: Option<AbsPathBuf>,
+    workspace: RustLibSrcWorkspace,
     error: Option<String>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
-pub(crate) enum SysrootWorkspace {
+pub enum RustLibSrcWorkspace {
     Workspace(CargoWorkspace),
     Stitched(Stitched),
     Empty,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
-pub(crate) struct Stitched {
-    crates: Arena<SysrootCrateData>,
+pub struct Stitched {
+    crates: Arena<RustLibSrcCrateData>,
 }
 
-impl ops::Index<SysrootCrate> for Stitched {
-    type Output = SysrootCrateData;
-    fn index(&self, index: SysrootCrate) -> &SysrootCrateData {
+impl ops::Index<RustLibSrcCrate> for Stitched {
+    type Output = RustLibSrcCrateData;
+    fn index(&self, index: RustLibSrcCrate) -> &RustLibSrcCrateData {
         &self.crates[index]
     }
 }
 
 impl Stitched {
-    pub(crate) fn public_deps(&self) -> impl Iterator<Item = (CrateName, SysrootCrate, bool)> + '_ {
+    pub(crate) fn public_deps(
+        &self,
+    ) -> impl Iterator<Item = (CrateName, RustLibSrcCrate, bool)> + '_ {
         // core is added as a dependency before std in order to
         // mimic rustcs dependency order
         [("core", true), ("alloc", false), ("std", true), ("test", false)].into_iter().filter_map(
@@ -63,32 +65,37 @@ impl Stitched {
         )
     }
 
-    pub(crate) fn proc_macro(&self) -> Option<SysrootCrate> {
+    pub(crate) fn proc_macro(&self) -> Option<RustLibSrcCrate> {
         self.by_name("proc_macro")
     }
 
-    pub(crate) fn crates(&self) -> impl ExactSizeIterator<Item = SysrootCrate> + '_ {
+    pub(crate) fn crates(&self) -> impl ExactSizeIterator<Item = RustLibSrcCrate> + '_ {
         self.crates.iter().map(|(id, _data)| id)
     }
 
-    fn by_name(&self, name: &str) -> Option<SysrootCrate> {
+    fn by_name(&self, name: &str) -> Option<RustLibSrcCrate> {
         let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
         Some(id)
     }
 }
 
-pub(crate) type SysrootCrate = Idx<SysrootCrateData>;
+pub(crate) type RustLibSrcCrate = Idx<RustLibSrcCrateData>;
 
 #[derive(Debug, Clone, Eq, PartialEq)]
-pub(crate) struct SysrootCrateData {
+pub(crate) struct RustLibSrcCrateData {
     pub(crate) name: String,
     pub(crate) root: ManifestPath,
-    pub(crate) deps: Vec<SysrootCrate>,
+    pub(crate) deps: Vec<RustLibSrcCrate>,
 }
 
 impl Sysroot {
     pub const fn empty() -> Sysroot {
-        Sysroot { root: None, src_root: None, workspace: SysrootWorkspace::Empty, error: None }
+        Sysroot {
+            root: None,
+            rust_lib_src_root: None,
+            workspace: RustLibSrcWorkspace::Empty,
+            error: None,
+        }
     }
 
     /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/`
@@ -100,15 +107,15 @@ impl Sysroot {
 
     /// Returns the sysroot "source" directory, where stdlib sources are located, like:
     /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library`
-    pub fn src_root(&self) -> Option<&AbsPath> {
-        self.src_root.as_deref()
+    pub fn rust_lib_src_root(&self) -> Option<&AbsPath> {
+        self.rust_lib_src_root.as_deref()
     }
 
-    pub fn is_empty(&self) -> bool {
+    pub fn is_rust_lib_src_empty(&self) -> bool {
         match &self.workspace {
-            SysrootWorkspace::Workspace(ws) => ws.packages().next().is_none(),
-            SysrootWorkspace::Stitched(stitched) => stitched.crates.is_empty(),
-            SysrootWorkspace::Empty => true,
+            RustLibSrcWorkspace::Workspace(ws) => ws.packages().next().is_none(),
+            RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.is_empty(),
+            RustLibSrcWorkspace::Empty => true,
         }
     }
 
@@ -118,13 +125,13 @@ impl Sysroot {
 
     pub fn num_packages(&self) -> usize {
         match &self.workspace {
-            SysrootWorkspace::Workspace(ws) => ws.packages().count(),
-            SysrootWorkspace::Stitched(c) => c.crates().count(),
-            SysrootWorkspace::Empty => 0,
+            RustLibSrcWorkspace::Workspace(ws) => ws.packages().count(),
+            RustLibSrcWorkspace::Stitched(c) => c.crates().count(),
+            RustLibSrcWorkspace::Empty => 0,
         }
     }
 
-    pub(crate) fn workspace(&self) -> &SysrootWorkspace {
+    pub(crate) fn workspace(&self) -> &RustLibSrcWorkspace {
         &self.workspace
     }
 }
@@ -133,33 +140,33 @@ impl Sysroot {
     /// Attempts to discover the toolchain's sysroot from the given `dir`.
     pub fn discover(dir: &AbsPath, extra_env: &FxHashMap<String, String>) -> Sysroot {
         let sysroot_dir = discover_sysroot_dir(dir, extra_env);
-        let sysroot_src_dir = sysroot_dir.as_ref().ok().map(|sysroot_dir| {
-            discover_sysroot_src_dir_or_add_component(sysroot_dir, dir, extra_env)
+        let rust_lib_src_dir = sysroot_dir.as_ref().ok().map(|sysroot_dir| {
+            discover_rust_lib_src_dir_or_add_component(sysroot_dir, dir, extra_env)
         });
-        Sysroot::assemble(Some(sysroot_dir), sysroot_src_dir)
+        Sysroot::assemble(Some(sysroot_dir), rust_lib_src_dir)
     }
 
     pub fn discover_with_src_override(
         current_dir: &AbsPath,
         extra_env: &FxHashMap<String, String>,
-        sysroot_src_dir: AbsPathBuf,
+        rust_lib_src_dir: AbsPathBuf,
     ) -> Sysroot {
         let sysroot_dir = discover_sysroot_dir(current_dir, extra_env);
-        Sysroot::assemble(Some(sysroot_dir), Some(Ok(sysroot_src_dir)))
+        Sysroot::assemble(Some(sysroot_dir), Some(Ok(rust_lib_src_dir)))
     }
 
-    pub fn discover_sysroot_src_dir(sysroot_dir: AbsPathBuf) -> Sysroot {
-        let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir)
+    pub fn discover_rust_lib_src_dir(sysroot_dir: AbsPathBuf) -> Sysroot {
+        let rust_lib_src_dir = discover_rust_lib_src_dir(&sysroot_dir)
             .ok_or_else(|| format_err!("can't find standard library sources in {sysroot_dir}"));
-        Sysroot::assemble(Some(Ok(sysroot_dir)), Some(sysroot_src_dir))
+        Sysroot::assemble(Some(Ok(sysroot_dir)), Some(rust_lib_src_dir))
     }
 
     pub fn discover_rustc_src(&self) -> Option<ManifestPath> {
         get_rustc_src(self.root()?)
     }
 
-    pub fn new(sysroot_dir: Option<AbsPathBuf>, sysroot_src_dir: Option<AbsPathBuf>) -> Sysroot {
-        Self::assemble(sysroot_dir.map(Ok), sysroot_src_dir.map(Ok))
+    pub fn new(sysroot_dir: Option<AbsPathBuf>, rust_lib_src_dir: Option<AbsPathBuf>) -> Sysroot {
+        Self::assemble(sysroot_dir.map(Ok), rust_lib_src_dir.map(Ok))
     }
 
     /// Returns a command to run a tool preferring the cargo proxies if the sysroot exists.
@@ -200,7 +207,7 @@ impl Sysroot {
 
     fn assemble(
         sysroot_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
-        sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
+        rust_lib_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
     ) -> Sysroot {
         let mut errors = String::new();
         let root = match sysroot_dir {
@@ -211,8 +218,8 @@ impl Sysroot {
             }
             None => None,
         };
-        let src_root = match sysroot_src_dir {
-            Some(Ok(sysroot_src_dir)) => Some(sysroot_src_dir),
+        let rust_lib_src_root = match rust_lib_src_dir {
+            Some(Ok(rust_lib_src_dir)) => Some(rust_lib_src_dir),
             Some(Err(e)) => {
                 format_to!(errors, "{e}\n");
                 None
@@ -221,24 +228,28 @@ impl Sysroot {
         };
         Sysroot {
             root,
-            src_root,
-            workspace: SysrootWorkspace::Empty,
+            rust_lib_src_root,
+            workspace: RustLibSrcWorkspace::Empty,
             error: errors.is_empty().not().then_some(errors),
         }
     }
 
-    pub fn load_workspace(&mut self, sysroot_source_config: &SysrootSourceWorkspaceConfig) {
-        assert!(matches!(self.workspace, SysrootWorkspace::Empty), "workspace already loaded");
-        let Self { root: _, src_root: Some(src_root), workspace, error: _ } = self else { return };
-        if let SysrootSourceWorkspaceConfig::CargoMetadata(cargo_config) = sysroot_source_config {
+    pub fn load_workspace(
+        &self,
+        sysroot_source_config: &RustSourceWorkspaceConfig,
+    ) -> Option<RustLibSrcWorkspace> {
+        assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded");
+        let Self { root: _, rust_lib_src_root: Some(src_root), workspace: _, error: _ } = self
+        else {
+            return None;
+        };
+        if let RustSourceWorkspaceConfig::CargoMetadata(cargo_config) = sysroot_source_config {
             let library_manifest = ManifestPath::try_from(src_root.join("Cargo.toml")).unwrap();
             if fs::metadata(&library_manifest).is_ok() {
                 if let Some(loaded) =
-                    Self::load_library_via_cargo(library_manifest, src_root, cargo_config)
+                    self.load_library_via_cargo(library_manifest, src_root, cargo_config)
                 {
-                    *workspace = loaded;
-                    self.load_core_check();
-                    return;
+                    return Some(loaded);
                 }
             }
         }
@@ -255,7 +266,7 @@ impl Sysroot {
                 .find(|it| fs::metadata(it).is_ok());
 
             if let Some(root) = root {
-                stitched.crates.alloc(SysrootCrateData {
+                stitched.crates.alloc(RustLibSrcCrateData {
                     name: name.into(),
                     root,
                     deps: Vec::new(),
@@ -286,21 +297,23 @@ impl Sysroot {
                 }
             }
         }
-        *workspace = SysrootWorkspace::Stitched(stitched);
-        self.load_core_check();
+        Some(RustLibSrcWorkspace::Stitched(stitched))
     }
 
-    fn load_core_check(&mut self) {
+    pub fn set_workspace(&mut self, workspace: RustLibSrcWorkspace) {
+        self.workspace = workspace;
         if self.error.is_none() {
-            if let Some(src_root) = &self.src_root {
+            if let Some(src_root) = &self.rust_lib_src_root {
                 let has_core = match &self.workspace {
-                    SysrootWorkspace::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
-                    SysrootWorkspace::Stitched(stitched) => stitched.by_name("core").is_some(),
-                    SysrootWorkspace::Empty => true,
+                    RustLibSrcWorkspace::Workspace(ws) => {
+                        ws.packages().any(|p| ws[p].name == "core")
+                    }
+                    RustLibSrcWorkspace::Stitched(stitched) => stitched.by_name("core").is_some(),
+                    RustLibSrcWorkspace::Empty => true,
                 };
                 if !has_core {
-                    let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
-                        " (env var `RUST_SRC_PATH` is set and may be incorrect, try unsetting it)"
+                    let var_note = if env::var_os("rust_lib_src_PATH").is_some() {
+                        " (env var `rust_lib_src_PATH` is set and may be incorrect, try unsetting it)"
                     } else {
                         ", try running `rustup component add rust-src` to possibly fix this"
                     };
@@ -313,10 +326,11 @@ impl Sysroot {
     }
 
     fn load_library_via_cargo(
+        &self,
         library_manifest: ManifestPath,
-        sysroot_src_dir: &AbsPathBuf,
+        rust_lib_src_dir: &AbsPathBuf,
         cargo_config: &CargoMetadataConfig,
-    ) -> Option<SysrootWorkspace> {
+    ) -> Option<RustLibSrcWorkspace> {
         tracing::debug!("Loading library metadata: {library_manifest}");
         let mut cargo_config = cargo_config.clone();
         // the sysroot uses `public-dependency`, so we make cargo think it's a nightly
@@ -327,9 +341,9 @@ impl Sysroot {
 
         let (mut res, _) = match CargoWorkspace::fetch_metadata(
             &library_manifest,
-            sysroot_src_dir,
+            rust_lib_src_dir,
             &cargo_config,
-            &Sysroot::empty(),
+            self,
             // Make sure we never attempt to write to the sysroot
             true,
             &|_| (),
@@ -391,7 +405,7 @@ impl Sysroot {
         });
 
         let cargo_workspace = CargoWorkspace::new(res, library_manifest, Default::default());
-        Some(SysrootWorkspace::Workspace(cargo_workspace))
+        Some(RustLibSrcWorkspace::Workspace(cargo_workspace))
     }
 }
 
@@ -407,36 +421,38 @@ fn discover_sysroot_dir(
     Ok(AbsPathBuf::assert(Utf8PathBuf::from(stdout)))
 }
 
-fn discover_sysroot_src_dir(sysroot_path: &AbsPathBuf) -> Option<AbsPathBuf> {
-    if let Ok(path) = env::var("RUST_SRC_PATH") {
+fn discover_rust_lib_src_dir(sysroot_path: &AbsPathBuf) -> Option<AbsPathBuf> {
+    if let Ok(path) = env::var("rust_lib_src_PATH") {
         if let Ok(path) = AbsPathBuf::try_from(path.as_str()) {
             let core = path.join("core");
             if fs::metadata(&core).is_ok() {
-                tracing::debug!("Discovered sysroot by RUST_SRC_PATH: {path}");
+                tracing::debug!("Discovered sysroot by rust_lib_src_PATH: {path}");
                 return Some(path);
             }
-            tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {core:?}), ignoring");
+            tracing::debug!(
+                "rust_lib_src_PATH is set, but is invalid (no core: {core:?}), ignoring"
+            );
         } else {
-            tracing::debug!("RUST_SRC_PATH is set, but is invalid, ignoring");
+            tracing::debug!("rust_lib_src_PATH is set, but is invalid, ignoring");
         }
     }
 
-    get_rust_src(sysroot_path)
+    get_rust_lib_src(sysroot_path)
 }
 
-fn discover_sysroot_src_dir_or_add_component(
+fn discover_rust_lib_src_dir_or_add_component(
     sysroot_path: &AbsPathBuf,
     current_dir: &AbsPath,
     extra_env: &FxHashMap<String, String>,
 ) -> Result<AbsPathBuf> {
-    discover_sysroot_src_dir(sysroot_path)
+    discover_rust_lib_src_dir(sysroot_path)
         .or_else(|| {
             let mut rustup = toolchain::command(Tool::Rustup.prefer_proxy(), current_dir);
             rustup.envs(extra_env);
             rustup.args(["component", "add", "rust-src"]);
             tracing::info!("adding rust-src component by {:?}", rustup);
             utf8_stdout(&mut rustup).ok()?;
-            get_rust_src(sysroot_path)
+            get_rust_lib_src(sysroot_path)
         })
         .ok_or_else(|| {
             tracing::error!(%sysroot_path, "can't load standard library, try installing `rust-src`");
@@ -461,11 +477,11 @@ fn get_rustc_src(sysroot_path: &AbsPath) -> Option<ManifestPath> {
     }
 }
 
-fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
-    let rust_src = sysroot_path.join("lib/rustlib/src/rust/library");
-    tracing::debug!("checking sysroot library: {rust_src}");
-    if fs::metadata(&rust_src).is_ok() {
-        Some(rust_src)
+fn get_rust_lib_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
+    let rust_lib_src = sysroot_path.join("lib/rustlib/src/rust/library");
+    tracing::debug!("checking sysroot library: {rust_lib_src}");
+    if fs::metadata(&rust_lib_src).is_ok() {
+        Some(rust_lib_src)
     } else {
         None
     }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index 28560865436..54eb0e3478a 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -12,9 +12,9 @@ use span::FileId;
 use triomphe::Arc;
 
 use crate::{
-    sysroot::SysrootWorkspace, workspace::ProjectWorkspaceKind, CargoWorkspace, CfgOverrides,
-    ManifestPath, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot,
-    SysrootSourceWorkspaceConfig, WorkspaceBuildScripts,
+    sysroot::RustLibSrcWorkspace, workspace::ProjectWorkspaceKind, CargoWorkspace, CfgOverrides,
+    ManifestPath, ProjectJson, ProjectJsonData, ProjectWorkspace, RustSourceWorkspaceConfig,
+    Sysroot, WorkspaceBuildScripts,
 };
 
 fn load_cargo(file: &str) -> (CrateGraph, ProcMacroPaths) {
@@ -42,7 +42,6 @@ fn load_workspace_from_metadata(file: &str) -> ProjectWorkspace {
             build_scripts: WorkspaceBuildScripts::default(),
             rustc: Err(None),
             error: None,
-            set_test: true,
         },
         cfg_overrides: Default::default(),
         sysroot: Sysroot::empty(),
@@ -50,6 +49,7 @@ fn load_workspace_from_metadata(file: &str) -> ProjectWorkspace {
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
         extra_includes: Vec::new(),
+        set_test: true,
     }
 }
 
@@ -65,6 +65,7 @@ fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) {
         target_layout: Err(Arc::from("test has no data layout")),
         cfg_overrides: Default::default(),
         extra_includes: Vec::new(),
+        set_test: true,
     };
     to_crate_graph(project_workspace, &mut Default::default())
 }
@@ -125,7 +126,10 @@ fn get_fake_sysroot() -> Sysroot {
     let sysroot_dir = AbsPathBuf::assert(sysroot_path);
     let sysroot_src_dir = sysroot_dir.clone();
     let mut sysroot = Sysroot::new(Some(sysroot_dir), Some(sysroot_src_dir));
-    sysroot.load_workspace(&SysrootSourceWorkspaceConfig::default_cargo());
+    let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo());
+    if let Some(loaded_sysroot) = loaded_sysroot {
+        sysroot.set_workspace(loaded_sysroot);
+    }
     sysroot
 }
 
@@ -271,15 +275,17 @@ fn smoke_test_real_sysroot_cargo() {
         AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
         &Default::default(),
     );
-    sysroot.load_workspace(&SysrootSourceWorkspaceConfig::default_cargo());
-    assert!(matches!(sysroot.workspace(), SysrootWorkspace::Workspace(_)));
+    let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo());
+    if let Some(loaded_sysroot) = loaded_sysroot {
+        sysroot.set_workspace(loaded_sysroot);
+    }
+    assert!(matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace(_)));
     let project_workspace = ProjectWorkspace {
         kind: ProjectWorkspaceKind::Cargo {
             cargo: cargo_workspace,
             build_scripts: WorkspaceBuildScripts::default(),
             rustc: Err(None),
             error: None,
-            set_test: true,
         },
         sysroot,
         rustc_cfg: Vec::new(),
@@ -287,6 +293,7 @@ fn smoke_test_real_sysroot_cargo() {
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
         extra_includes: Vec::new(),
+        set_test: true,
     };
     project_workspace.to_crate_graph(
         &mut {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index dcd62753cb2..f5d46daa80f 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -2,7 +2,7 @@
 //! metadata` or `rust-project.json`) into representation stored in the salsa
 //! database -- `CrateGraph`.
 
-use std::{collections::VecDeque, fmt, fs, iter, ops::Deref, sync};
+use std::{collections::VecDeque, fmt, fs, iter, ops::Deref, sync, thread};
 
 use anyhow::Context;
 use base_db::{
@@ -23,10 +23,10 @@ use crate::{
     cargo_workspace::{CargoMetadataConfig, DepKind, PackageData, RustLibSource},
     env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env},
     project_json::{Crate, CrateArrayIdx},
-    sysroot::{SysrootCrate, SysrootWorkspace},
+    sysroot::{RustLibSrcCrate, RustLibSrcWorkspace},
     toolchain_info::{rustc_cfg, target_data_layout, target_tuple, version, QueryConfig},
     CargoConfig, CargoWorkspace, CfgOverrides, InvocationStrategy, ManifestPath, Package,
-    ProjectJson, ProjectManifest, Sysroot, SysrootSourceWorkspaceConfig, TargetData, TargetKind,
+    ProjectJson, ProjectManifest, RustSourceWorkspaceConfig, Sysroot, TargetData, TargetKind,
     WorkspaceBuildScripts,
 };
 use tracing::{debug, error, info};
@@ -64,6 +64,8 @@ pub struct ProjectWorkspace {
     pub cfg_overrides: CfgOverrides,
     /// Additional includes to add for the VFS.
     pub extra_includes: Vec<AbsPathBuf>,
+    /// Set `cfg(test)` for local crates
+    pub set_test: bool,
 }
 
 #[derive(Clone)]
@@ -79,7 +81,6 @@ pub enum ProjectWorkspaceKind {
         /// The rustc workspace loaded for this workspace. An `Err(None)` means loading has been
         /// disabled or was otherwise not requested.
         rustc: Result<Box<(CargoWorkspace, WorkspaceBuildScripts)>, Option<String>>,
-        set_test: bool,
     },
     /// Project workspace was specified using a `rust-project.json` file.
     Json(ProjectJson),
@@ -98,7 +99,6 @@ pub enum ProjectWorkspaceKind {
         file: ManifestPath,
         /// Is this file a cargo script file?
         cargo: Option<(CargoWorkspace, WorkspaceBuildScripts, Option<Arc<anyhow::Error>>)>,
-        set_test: bool,
     },
 }
 
@@ -113,9 +113,10 @@ impl fmt::Debug for ProjectWorkspace {
             target_layout,
             cfg_overrides,
             extra_includes,
+            set_test,
         } = self;
         match kind {
-            ProjectWorkspaceKind::Cargo { cargo, error: _, build_scripts, rustc, set_test } => f
+            ProjectWorkspaceKind::Cargo { cargo, error: _, build_scripts, rustc } => f
                 .debug_struct("Cargo")
                 .field("root", &cargo.workspace_root().file_name())
                 .field("n_packages", &cargo.packages().len())
@@ -141,11 +142,12 @@ impl fmt::Debug for ProjectWorkspace {
                     .field("toolchain", &toolchain)
                     .field("data_layout", &target_layout)
                     .field("n_cfg_overrides", &cfg_overrides.len())
-                    .field("n_extra_includes", &extra_includes.len());
+                    .field("n_extra_includes", &extra_includes.len())
+                    .field("set_test", set_test);
 
                 debug_struct.finish()
             }
-            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, set_test } => f
+            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script } => f
                 .debug_struct("DetachedFiles")
                 .field("file", &file)
                 .field("cargo_script", &cargo_script.is_some())
@@ -186,7 +188,7 @@ impl ProjectWorkspace {
                 let project_location = project_json.parent().to_path_buf();
                 let project_json: ProjectJson =
                     ProjectJson::new(Some(project_json.clone()), &project_location, data);
-                ProjectWorkspace::load_inline(project_json, config)
+                ProjectWorkspace::load_inline(project_json, config, progress)
             }
             ProjectManifest::CargoScript(rust_file) => {
                 ProjectWorkspace::load_detached_file(rust_file, config)?
@@ -204,19 +206,33 @@ impl ProjectWorkspace {
         config: &CargoConfig,
         progress: &dyn Fn(String),
     ) -> Result<ProjectWorkspace, anyhow::Error> {
-        let mut sysroot = match (&config.sysroot, &config.sysroot_src) {
+        progress("Discovering sysroot".to_owned());
+        let CargoConfig {
+            features,
+            rustc_source,
+            extra_args,
+            extra_env,
+            set_test,
+            cfg_overrides,
+            extra_includes,
+            sysroot,
+            sysroot_src,
+            target,
+            ..
+        } = config;
+        let mut sysroot = match (sysroot, sysroot_src) {
             (Some(RustLibSource::Discover), None) => {
-                Sysroot::discover(cargo_toml.parent(), &config.extra_env)
+                Sysroot::discover(cargo_toml.parent(), extra_env)
             }
             (Some(RustLibSource::Discover), Some(sysroot_src)) => {
                 Sysroot::discover_with_src_override(
                     cargo_toml.parent(),
-                    &config.extra_env,
+                    extra_env,
                     sysroot_src.clone(),
                 )
             }
             (Some(RustLibSource::Path(path)), None) => {
-                Sysroot::discover_sysroot_src_dir(path.clone())
+                Sysroot::discover_rust_lib_src_dir(path.clone())
             }
             (Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => {
                 Sysroot::new(Some(sysroot.clone()), Some(sysroot_src.clone()))
@@ -224,100 +240,147 @@ impl ProjectWorkspace {
             (None, _) => Sysroot::empty(),
         };
 
-        let rustc_dir = match &config.rustc_source {
-            Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone())
-                .map_err(|p| Some(format!("rustc source path is not absolute: {p}"))),
-            Some(RustLibSource::Discover) => sysroot
-                .discover_rustc_src()
-                .ok_or_else(|| Some("Failed to discover rustc source for sysroot.".to_owned())),
-            None => Err(None),
-        };
-
-        tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.src_root(), root = ?sysroot.root(), "Using sysroot");
+        tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.rust_lib_src_root(), root = ?sysroot.root(), "Using sysroot");
+        progress("Querying project metadata".to_owned());
         let toolchain_config = QueryConfig::Cargo(&sysroot, cargo_toml);
         let targets =
-            target_tuple::get(toolchain_config, config.target.as_deref(), &config.extra_env)
-                .unwrap_or_default();
-        let toolchain = version::get(toolchain_config, &config.extra_env)
-            .inspect_err(|e| {
-                tracing::error!(%e,
-                    "failed fetching toolchain version for {cargo_toml:?} workspace"
-                )
-            })
-            .ok()
-            .flatten();
-        let rustc_cfg =
-            rustc_cfg::get(toolchain_config, targets.first().map(Deref::deref), &config.extra_env);
-        let cfg_overrides = config.cfg_overrides.clone();
-        let data_layout = target_data_layout::get(
-            toolchain_config,
-            targets.first().map(Deref::deref),
-            &config.extra_env,
-        );
-        if let Err(e) = &data_layout {
-            tracing::error!(%e, "failed fetching data layout for {cargo_toml:?} workspace");
-        }
-        sysroot.load_workspace(&SysrootSourceWorkspaceConfig::CargoMetadata(
-            sysroot_metadata_config(&config.extra_env, &targets),
-        ));
+            target_tuple::get(toolchain_config, target.as_deref(), extra_env).unwrap_or_default();
+
+        // We spawn a bunch of processes to query various information about the workspace's
+        // toolchain and sysroot
+        // We can speed up loading a bit by spawning all of these processes in parallel (especially
+        // on systems were process spawning is delayed)
+        let join = thread::scope(|s| {
+            let workspace_dir = cargo_toml.parent();
+            let toolchain = s.spawn(|| {
+                version::get(toolchain_config, extra_env)
+                    .inspect_err(|e| {
+                        tracing::error!(%e,
+                            "failed fetching toolchain version for {cargo_toml:?} workspace"
+                        )
+                    })
+                    .ok()
+                    .flatten()
+            });
 
-        let rustc = rustc_dir.and_then(|rustc_dir| {
-            info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
-            match CargoWorkspace::fetch_metadata(
-                &rustc_dir,
-                cargo_toml.parent(),
-                &CargoMetadataConfig {
-                    features: crate::CargoFeatures::default(),
-                    targets: targets.clone(),
-                    extra_args: config.extra_args.clone(),
-                    extra_env: config.extra_env.clone(),
-                },
-                &sysroot,
-                false,
-                progress,
-            ) {
-                Ok((meta, _error)) => {
-                    let workspace = CargoWorkspace::new(meta, cargo_toml.clone(), Env::default());
-                    let build_scripts = WorkspaceBuildScripts::rustc_crates(
-                        &workspace,
-                        cargo_toml.parent(),
-                        &config.extra_env,
+            let rustc_cfg = s.spawn(|| {
+                rustc_cfg::get(toolchain_config, targets.first().map(Deref::deref), extra_env)
+            });
+            let data_layout = s.spawn(|| {
+                target_data_layout::get(
+                    toolchain_config,
+                    targets.first().map(Deref::deref),
+                    extra_env,
+                ).inspect_err(|e| {
+                    tracing::error!(%e, "failed fetching data layout for {cargo_toml:?} workspace")
+                })
+            });
+
+            let rustc_dir = s.spawn(|| {
+                let rustc_dir = match rustc_source {
+                    Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone())
+                        .map_err(|p| Some(format!("rustc source path is not absolute: {p}"))),
+                    Some(RustLibSource::Discover) => {
+                        sysroot.discover_rustc_src().ok_or_else(|| {
+                            Some("Failed to discover rustc source for sysroot.".to_owned())
+                        })
+                    }
+                    None => Err(None),
+                };
+                rustc_dir.and_then(|rustc_dir| {
+                    info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
+                    match CargoWorkspace::fetch_metadata(
+                        &rustc_dir,
+                        workspace_dir,
+                        &CargoMetadataConfig {
+                            features: crate::CargoFeatures::default(),
+                            targets: targets.clone(),
+                            extra_args: extra_args.clone(),
+                            extra_env: extra_env.clone(),
+                        },
                         &sysroot,
-                    );
-                    Ok(Box::new((workspace, build_scripts)))
-                }
-                Err(e) => {
-                    tracing::error!(
-                        %e,
-                        "Failed to read Cargo metadata from rustc source at {rustc_dir}",
-                    );
-                    Err(Some(format!(
-                        "Failed to read Cargo metadata from rustc source at {rustc_dir}: {e}"
-                    )))
-                }
-            }
+                        false,
+                        &|_| (),
+                    ) {
+                        Ok((meta, _error)) => {
+                            let workspace =
+                                CargoWorkspace::new(meta, cargo_toml.clone(), Env::default());
+                            let build_scripts = WorkspaceBuildScripts::rustc_crates(
+                                &workspace,
+                                workspace_dir,
+                                extra_env,
+                                &sysroot,
+                            );
+                            Ok(Box::new((workspace, build_scripts)))
+                        }
+                        Err(e) => {
+                            tracing::error!(
+                                %e,
+                                "Failed to read Cargo metadata from rustc source at {rustc_dir}",
+                            );
+                            Err(Some(format!(
+                            "Failed to read Cargo metadata from rustc source at {rustc_dir}: {e}"
+                        )))
+                        }
+                    }
+                })
+            });
+
+            let cargo_metadata = s.spawn(|| {
+                CargoWorkspace::fetch_metadata(
+                    cargo_toml,
+                    workspace_dir,
+                    &CargoMetadataConfig {
+                        features: features.clone(),
+                        targets: targets.clone(),
+                        extra_args: extra_args.clone(),
+                        extra_env: extra_env.clone(),
+                    },
+                    &sysroot,
+                    false,
+                    &|_| (),
+                )
+            });
+            let loaded_sysroot = s.spawn(|| {
+                sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata(
+                    sysroot_metadata_config(extra_env, &targets),
+                ))
+            });
+            let cargo_config_extra_env =
+                s.spawn(|| cargo_config_env(cargo_toml, extra_env, &sysroot));
+            thread::Result::Ok((
+                toolchain.join()?,
+                rustc_cfg.join()?,
+                data_layout.join()?,
+                rustc_dir.join()?,
+                loaded_sysroot.join()?,
+                cargo_metadata.join()?,
+                cargo_config_extra_env.join()?,
+            ))
         });
 
-        let (meta, error) = CargoWorkspace::fetch_metadata(
-            cargo_toml,
-            cargo_toml.parent(),
-            &CargoMetadataConfig {
-                features: config.features.clone(),
-                targets,
-                extra_args: config.extra_args.clone(),
-                extra_env: config.extra_env.clone(),
-            },
-            &sysroot,
-            false,
-            progress,
-        )
-        .with_context(|| {
+        let (
+            toolchain,
+            rustc_cfg,
+            data_layout,
+            rustc,
+            loaded_sysroot,
+            cargo_metadata,
+            cargo_config_extra_env,
+        ) = match join {
+            Ok(it) => it,
+            Err(e) => std::panic::resume_unwind(e),
+        };
+
+        let (meta, error) = cargo_metadata.with_context(|| {
             format!(
                 "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
             )
         })?;
-        let cargo_config_extra_env = cargo_config_env(cargo_toml, &config.extra_env, &sysroot);
         let cargo = CargoWorkspace::new(meta, cargo_toml.clone(), cargo_config_extra_env);
+        if let Some(loaded_sysroot) = loaded_sysroot {
+            sysroot.set_workspace(loaded_sysroot);
+        }
 
         Ok(ProjectWorkspace {
             kind: ProjectWorkspaceKind::Cargo {
@@ -325,35 +388,70 @@ impl ProjectWorkspace {
                 build_scripts: WorkspaceBuildScripts::default(),
                 rustc,
                 error: error.map(Arc::new),
-                set_test: config.set_test,
             },
             sysroot,
             rustc_cfg,
-            cfg_overrides,
+            cfg_overrides: cfg_overrides.clone(),
             toolchain,
             target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
-            extra_includes: config.extra_includes.clone(),
+            extra_includes: extra_includes.clone(),
+            set_test: *set_test,
         })
     }
 
-    pub fn load_inline(project_json: ProjectJson, config: &CargoConfig) -> ProjectWorkspace {
+    pub fn load_inline(
+        project_json: ProjectJson,
+        config: &CargoConfig,
+        progress: &dyn Fn(String),
+    ) -> ProjectWorkspace {
+        progress("Discovering sysroot".to_owned());
         let mut sysroot =
             Sysroot::new(project_json.sysroot.clone(), project_json.sysroot_src.clone());
-        sysroot.load_workspace(&SysrootSourceWorkspaceConfig::Stitched);
+        let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::Stitched);
+        if let Some(loaded_sysroot) = loaded_sysroot {
+            sysroot.set_workspace(loaded_sysroot);
+        }
+
+        tracing::info!(workspace = %project_json.manifest_or_root(), src_root = ?sysroot.rust_lib_src_root(), root = ?sysroot.root(), "Using sysroot");
+        progress("Querying project metadata".to_owned());
         let query_config = QueryConfig::Rustc(&sysroot, project_json.path().as_ref());
-        let toolchain = version::get(query_config, &config.extra_env).ok().flatten();
+        let targets = target_tuple::get(query_config, config.target.as_deref(), &config.extra_env)
+            .unwrap_or_default();
+
+        // We spawn a bunch of processes to query various information about the workspace's
+        // toolchain and sysroot
+        // We can speed up loading a bit by spawning all of these processes in parallel (especially
+        // on systems were process spawning is delayed)
+        let join = thread::scope(|s| {
+            let toolchain =
+                s.spawn(|| version::get(query_config, &config.extra_env).ok().flatten());
+            let rustc_cfg = s.spawn(|| {
+                rustc_cfg::get(query_config, targets.first().map(Deref::deref), &config.extra_env)
+            });
+            let data_layout = s.spawn(|| {
+                target_data_layout::get(
+                    query_config,
+                    targets.first().map(Deref::deref),
+                    &config.extra_env,
+                )
+            });
+            thread::Result::Ok((toolchain.join()?, rustc_cfg.join()?, data_layout.join()?))
+        });
+
+        let (toolchain, rustc_cfg, target_layout) = match join {
+            Ok(it) => it,
+            Err(e) => std::panic::resume_unwind(e),
+        };
 
-        let target = config.target.as_deref();
-        let rustc_cfg = rustc_cfg::get(query_config, target, &config.extra_env);
-        let data_layout = target_data_layout::get(query_config, target, &config.extra_env);
         ProjectWorkspace {
             kind: ProjectWorkspaceKind::Json(project_json),
             sysroot,
             rustc_cfg,
             toolchain,
-            target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
+            target_layout: target_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
             cfg_overrides: config.cfg_overrides.clone(),
             extra_includes: config.extra_includes.clone(),
+            set_test: config.set_test,
         }
     }
 
@@ -363,7 +461,7 @@ impl ProjectWorkspace {
     ) -> anyhow::Result<ProjectWorkspace> {
         let dir = detached_file.parent();
         let mut sysroot = match &config.sysroot {
-            Some(RustLibSource::Path(path)) => Sysroot::discover_sysroot_src_dir(path.clone()),
+            Some(RustLibSource::Path(path)) => Sysroot::discover_rust_lib_src_dir(path.clone()),
             Some(RustLibSource::Discover) => Sysroot::discover(dir, &config.extra_env),
             None => Sysroot::empty(),
         };
@@ -374,9 +472,12 @@ impl ProjectWorkspace {
             .unwrap_or_default();
         let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env);
         let data_layout = target_data_layout::get(query_config, None, &config.extra_env);
-        sysroot.load_workspace(&SysrootSourceWorkspaceConfig::CargoMetadata(
+        let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata(
             sysroot_metadata_config(&config.extra_env, &targets),
         ));
+        if let Some(loaded_sysroot) = loaded_sysroot {
+            sysroot.set_workspace(loaded_sysroot);
+        }
 
         let cargo_script = CargoWorkspace::fetch_metadata(
             detached_file,
@@ -406,7 +507,6 @@ impl ProjectWorkspace {
             kind: ProjectWorkspaceKind::DetachedFile {
                 file: detached_file.to_owned(),
                 cargo: cargo_script,
-                set_test: config.set_test,
             },
             sysroot,
             rustc_cfg,
@@ -414,6 +514,7 @@ impl ProjectWorkspace {
             target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
             cfg_overrides: config.cfg_overrides.clone(),
             extra_includes: config.extra_includes.clone(),
+            set_test: config.set_test,
         })
     }
 
@@ -545,7 +646,7 @@ impl ProjectWorkspace {
     pub fn to_roots(&self) -> Vec<PackageRoot> {
         let mk_sysroot = || {
             let mut r = match self.sysroot.workspace() {
-                SysrootWorkspace::Workspace(ws) => ws
+                RustLibSrcWorkspace::Workspace(ws) => ws
                     .packages()
                     .filter_map(|pkg| {
                         if ws[pkg].is_local {
@@ -566,12 +667,17 @@ impl ProjectWorkspace {
                         Some(PackageRoot { is_local: false, include, exclude })
                     })
                     .collect(),
-                SysrootWorkspace::Stitched(_) | SysrootWorkspace::Empty => vec![],
+                RustLibSrcWorkspace::Stitched(_) | RustLibSrcWorkspace::Empty => vec![],
             };
 
             r.push(PackageRoot {
                 is_local: false,
-                include: self.sysroot.src_root().map(|it| it.to_path_buf()).into_iter().collect(),
+                include: self
+                    .sysroot
+                    .rust_lib_src_root()
+                    .map(|it| it.to_path_buf())
+                    .into_iter()
+                    .collect(),
                 exclude: Vec::new(),
             });
             r
@@ -593,7 +699,7 @@ impl ProjectWorkspace {
                 .into_iter()
                 .chain(mk_sysroot())
                 .collect::<Vec<_>>(),
-            ProjectWorkspaceKind::Cargo { cargo, rustc, build_scripts, error: _, set_test: _ } => {
+            ProjectWorkspaceKind::Cargo { cargo, rustc, build_scripts, error: _ } => {
                 cargo
                     .packages()
                     .map(|pkg| {
@@ -728,8 +834,9 @@ impl ProjectWorkspace {
                 sysroot,
                 extra_env,
                 cfg_overrides,
+                self.set_test,
             ),
-            ProjectWorkspaceKind::Cargo { cargo, rustc, build_scripts, error: _, set_test } => {
+            ProjectWorkspaceKind::Cargo { cargo, rustc, build_scripts, error: _ } => {
                 cargo_to_crate_graph(
                     load,
                     rustc.as_ref().map(|a| a.as_ref()).ok(),
@@ -738,10 +845,10 @@ impl ProjectWorkspace {
                     rustc_cfg.clone(),
                     cfg_overrides,
                     build_scripts,
-                    *set_test,
+                    self.set_test,
                 )
             }
-            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, set_test, .. } => {
+            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, .. } => {
                 if let Some((cargo, build_scripts, _)) = cargo_script {
                     cargo_to_crate_graph(
                         &mut |path| load(path),
@@ -751,7 +858,7 @@ impl ProjectWorkspace {
                         rustc_cfg.clone(),
                         cfg_overrides,
                         build_scripts,
-                        *set_test,
+                        self.set_test,
                     )
                 } else {
                     detached_file_to_crate_graph(
@@ -760,7 +867,7 @@ impl ProjectWorkspace {
                         file,
                         sysroot,
                         cfg_overrides,
-                        *set_test,
+                        self.set_test,
                     )
                 }
             }
@@ -782,34 +889,22 @@ impl ProjectWorkspace {
         } = other;
         (match (kind, o_kind) {
             (
-                ProjectWorkspaceKind::Cargo {
-                    cargo,
-                    rustc,
-                    build_scripts: _,
-                    error: _,
-                    set_test: _,
-                },
+                ProjectWorkspaceKind::Cargo { cargo, rustc, build_scripts: _, error: _ },
                 ProjectWorkspaceKind::Cargo {
                     cargo: o_cargo,
                     rustc: o_rustc,
                     build_scripts: _,
                     error: _,
-                    set_test: _,
                 },
             ) => cargo == o_cargo && rustc == o_rustc,
             (ProjectWorkspaceKind::Json(project), ProjectWorkspaceKind::Json(o_project)) => {
                 project == o_project
             }
             (
-                ProjectWorkspaceKind::DetachedFile {
-                    file,
-                    cargo: Some((cargo_script, _, _)),
-                    set_test: _,
-                },
+                ProjectWorkspaceKind::DetachedFile { file, cargo: Some((cargo_script, _, _)) },
                 ProjectWorkspaceKind::DetachedFile {
                     file: o_file,
                     cargo: Some((o_cargo_script, _, _)),
-                    set_test: _,
                 },
             ) => file == o_file && cargo_script == o_cargo_script,
             _ => return false,
@@ -837,13 +932,13 @@ fn project_json_to_crate_graph(
     sysroot: &Sysroot,
     extra_env: &FxHashMap<String, String>,
     override_cfg: &CfgOverrides,
+    set_test: bool,
 ) -> (CrateGraph, ProcMacroPaths) {
     let mut res = (CrateGraph::default(), ProcMacroPaths::default());
     let (crate_graph, proc_macros) = &mut res;
     let (public_deps, libproc_macro) =
         sysroot_to_crate_graph(crate_graph, sysroot, rustc_cfg.clone(), load);
 
-    let r_a_cfg_flag = CfgAtom::Flag(sym::rust_analyzer.clone());
     let mut cfg_cache: FxHashMap<&str, Vec<CfgAtom>> = FxHashMap::default();
 
     let idx_to_crate_id: FxHashMap<CrateArrayIdx, CrateId> = project
@@ -862,6 +957,7 @@ fn project_json_to_crate_graph(
                     proc_macro_dylib_path,
                     is_proc_macro,
                     repository,
+                    is_workspace_member,
                     ..
                 },
                 file_id,
@@ -879,19 +975,28 @@ fn project_json_to_crate_graph(
                     None => &rustc_cfg,
                 };
 
-                let mut cfg_options = target_cfgs
-                    .iter()
-                    .chain(cfg.iter())
-                    .chain(iter::once(&r_a_cfg_flag))
-                    .cloned()
-                    .collect();
-                override_cfg.apply(
-                    &mut cfg_options,
-                    display_name
-                        .as_ref()
-                        .map(|it| it.canonical_name().as_str())
-                        .unwrap_or_default(),
-                );
+                let cfg_options = {
+                    let mut cfg_options: CfgOptions =
+                        target_cfgs.iter().chain(cfg.iter()).cloned().collect();
+
+                    if *is_workspace_member {
+                        if set_test {
+                            // Add test cfg for local crates
+                            cfg_options.insert_atom(sym::test.clone());
+                        }
+                        cfg_options.insert_atom(sym::rust_analyzer.clone());
+                    }
+
+                    override_cfg.apply(
+                        &mut cfg_options,
+                        display_name
+                            .as_ref()
+                            .map(|it| it.canonical_name().as_str())
+                            .unwrap_or_default(),
+                    );
+                    cfg_options
+                };
+
                 let crate_graph_crate_id = crate_graph.add_crate_root(
                     file_id,
                     *edition,
@@ -1385,7 +1490,7 @@ fn sysroot_to_crate_graph(
 ) -> (SysrootPublicDeps, Option<CrateId>) {
     let _p = tracing::info_span!("sysroot_to_crate_graph").entered();
     match sysroot.workspace() {
-        SysrootWorkspace::Workspace(cargo) => {
+        RustLibSrcWorkspace::Workspace(cargo) => {
             let (mut cg, mut pm) = cargo_to_crate_graph(
                 load,
                 None,
@@ -1460,7 +1565,7 @@ fn sysroot_to_crate_graph(
 
             (SysrootPublicDeps { deps: pub_deps }, libproc_macro)
         }
-        SysrootWorkspace::Stitched(stitched) => {
+        RustLibSrcWorkspace::Stitched(stitched) => {
             let cfg_options = Arc::new({
                 let mut cfg_options = CfgOptions::default();
                 cfg_options.extend(rustc_cfg);
@@ -1468,7 +1573,7 @@ fn sysroot_to_crate_graph(
                 cfg_options.insert_atom(sym::miri.clone());
                 cfg_options
             });
-            let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = stitched
+            let sysroot_crates: FxHashMap<RustLibSrcCrate, CrateId> = stitched
                 .crates()
                 .filter_map(|krate| {
                     let file_id = load(&stitched[krate].root)?;
@@ -1513,7 +1618,7 @@ fn sysroot_to_crate_graph(
                 stitched.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
             (public_deps, libproc_macro)
         }
-        SysrootWorkspace::Empty => (SysrootPublicDeps { deps: vec![] }, None),
+        RustLibSrcWorkspace::Empty => (SysrootPublicDeps { deps: vec![] }, None),
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
index 2026ab2b8c2..587d3c17827 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
@@ -420,6 +420,7 @@
                 "group1_other_cfg=other_config",
                 "group2_cfg=yet_another_config",
                 "rust_analyzer",
+                "test",
                 "true",
             ],
         ),
@@ -496,6 +497,7 @@
                 "group2_cfg=fourth_config",
                 "group2_cfg=yet_another_config",
                 "rust_analyzer",
+                "test",
                 "true",
                 "unrelated_cfg",
             ],
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index a0e14b8fcb2..00805c79bcc 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -417,6 +417,7 @@
         cfg_options: CfgOptions(
             [
                 "rust_analyzer",
+                "test",
                 "true",
             ],
         ),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
index 199f61e70f0..e9ca12deaf6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -12,8 +12,8 @@ use paths::Utf8PathBuf;
 use profile::StopWatch;
 use project_model::toolchain_info::{target_data_layout, QueryConfig};
 use project_model::{
-    CargoConfig, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, RustLibSource, Sysroot,
-    SysrootSourceWorkspaceConfig,
+    CargoConfig, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, RustLibSource,
+    RustSourceWorkspaceConfig, Sysroot,
 };
 
 use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
@@ -75,7 +75,11 @@ impl Tester {
         };
 
         let mut sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env);
-        sysroot.load_workspace(&SysrootSourceWorkspaceConfig::default_cargo());
+        let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo());
+        if let Some(loaded_sysroot) = loaded_sysroot {
+            sysroot.set_workspace(loaded_sysroot);
+        }
+
         let data_layout = target_data_layout::get(
             QueryConfig::Rustc(&sysroot, tmp_file.parent().unwrap().as_ref()),
             None,
@@ -86,7 +90,6 @@ impl Tester {
             kind: ProjectWorkspaceKind::DetachedFile {
                 file: ManifestPath::try_from(tmp_file).unwrap(),
                 cargo: None,
-                set_test: true,
             },
             sysroot,
             rustc_cfg: vec![],
@@ -94,6 +97,7 @@ impl Tester {
             target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
             cfg_overrides: Default::default(),
             extra_includes: vec![],
+            set_test: true,
         };
         let load_cargo_config = LoadCargoConfig {
             load_out_dirs_from_check: false,
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 e915e55722b..d7e9a5c586c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -84,10 +84,10 @@ config_data! {
         completion_snippets_custom: FxHashMap<String, SnippetDef> = Config::completion_snippets_default(),
 
 
-        /// These directories will be ignored by rust-analyzer. They are
+        /// These paths (file/directories) will be ignored by rust-analyzer. They are
         /// relative to the workspace root, and globs are not supported. You may
         /// also need to add the folders to Code's `files.watcherExclude`.
-        files_excludeDirs: Vec<Utf8PathBuf> = vec![],
+        files_exclude | files_excludeDirs: Vec<Utf8PathBuf> = vec![],
 
 
 
@@ -1792,7 +1792,7 @@ impl Config {
 
     fn discovered_projects(&self) -> Vec<ManifestOrProjectJson> {
         let exclude_dirs: Vec<_> =
-            self.files_excludeDirs().iter().map(|p| self.root_path.join(p)).collect();
+            self.files_exclude().iter().map(|p| self.root_path.join(p)).collect();
 
         let mut projects = vec![];
         for fs_proj in &self.discovered_projects_from_filesystem {
@@ -1914,10 +1914,14 @@ impl Config {
                 }
                 _ => FilesWatcher::Server,
             },
-            exclude: self.files_excludeDirs().iter().map(|it| self.root_path.join(it)).collect(),
+            exclude: self.excluded().collect(),
         }
     }
 
+    pub fn excluded(&self) -> impl Iterator<Item = AbsPathBuf> + use<'_> {
+        self.files_exclude().iter().map(|it| self.root_path.join(it))
+    }
+
     pub fn notifications(&self) -> NotificationsConfig {
         NotificationsConfig {
             cargo_toml_not_found: self.notifications_cargoTomlNotFound().to_owned(),
@@ -3798,8 +3802,10 @@ mod tests {
         (config, _, _) = config.apply_change(change);
 
         assert_eq!(config.cargo_targetDir(None), &Some(TargetDirectory::UseSubdirectory(true)));
+        let target =
+            Utf8PathBuf::from(std::env::var("CARGO_TARGET_DIR").unwrap_or("target".to_owned()));
         assert!(
-            matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("target/rust-analyzer")))
+            matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(target.join("rust-analyzer")))
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index b52f64aaace..70105cda006 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -650,7 +650,8 @@ impl GlobalStateSnapshot {
         RwLockReadGuard::map(self.vfs.read(), |(it, _)| it)
     }
 
-    pub(crate) fn url_to_file_id(&self, url: &Url) -> anyhow::Result<FileId> {
+    /// Returns `None` if the file was excluded.
+    pub(crate) fn url_to_file_id(&self, url: &Url) -> anyhow::Result<Option<FileId>> {
         url_to_file_id(&self.vfs_read(), url)
     }
 
@@ -658,7 +659,8 @@ impl GlobalStateSnapshot {
         file_id_to_url(&self.vfs_read(), id)
     }
 
-    pub(crate) fn vfs_path_to_file_id(&self, vfs_path: &VfsPath) -> anyhow::Result<FileId> {
+    /// Returns `None` if the file was excluded.
+    pub(crate) fn vfs_path_to_file_id(&self, vfs_path: &VfsPath) -> anyhow::Result<Option<FileId>> {
         vfs_path_to_file_id(&self.vfs_read(), vfs_path)
     }
 
@@ -750,14 +752,21 @@ pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url {
     url_from_abs_path(path)
 }
 
-pub(crate) fn url_to_file_id(vfs: &vfs::Vfs, url: &Url) -> anyhow::Result<FileId> {
+/// Returns `None` if the file was excluded.
+pub(crate) fn url_to_file_id(vfs: &vfs::Vfs, url: &Url) -> anyhow::Result<Option<FileId>> {
     let path = from_proto::vfs_path(url)?;
-    let res = vfs.file_id(&path).ok_or_else(|| anyhow::format_err!("file not found: {path}"))?;
-    Ok(res)
+    vfs_path_to_file_id(vfs, &path)
 }
 
-pub(crate) fn vfs_path_to_file_id(vfs: &vfs::Vfs, vfs_path: &VfsPath) -> anyhow::Result<FileId> {
-    let res =
+/// Returns `None` if the file was excluded.
+pub(crate) fn vfs_path_to_file_id(
+    vfs: &vfs::Vfs,
+    vfs_path: &VfsPath,
+) -> anyhow::Result<Option<FileId>> {
+    let (file_id, excluded) =
         vfs.file_id(vfs_path).ok_or_else(|| anyhow::format_err!("file not found: {vfs_path}"))?;
-    Ok(res)
+    match excluded {
+        vfs::FileExcluded::Yes => Ok(None),
+        vfs::FileExcluded::No => Ok(Some(file_id)),
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
index 48856d19e15..55344a4d6ac 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
@@ -22,6 +22,7 @@ use crate::{
     mem_docs::DocumentData,
     reload,
     target_spec::TargetSpec,
+    try_default,
 };
 
 pub(crate) fn handle_cancel(state: &mut GlobalState, params: CancelParams) -> anyhow::Result<()> {
@@ -74,6 +75,14 @@ pub(crate) fn handle_did_open_text_document(
             tracing::error!("duplicate DidOpenTextDocument: {}", path);
         }
 
+        if let Some(abs_path) = path.as_path() {
+            if state.config.excluded().any(|excluded| abs_path.starts_with(&excluded)) {
+                tracing::trace!("opened excluded file {abs_path}");
+                state.vfs.write().0.insert_excluded_file(path);
+                return Ok(());
+            }
+        }
+
         let contents = params.text_document.text.into_bytes();
         state.vfs.write().0.set_file_contents(path, Some(contents));
         if state.config.discover_workspace_config().is_some() {
@@ -127,7 +136,8 @@ pub(crate) fn handle_did_close_text_document(
             tracing::error!("orphan DidCloseTextDocument: {}", path);
         }
 
-        if let Some(file_id) = state.vfs.read().0.file_id(&path) {
+        // Clear diagnostics also for excluded files, just in case.
+        if let Some((file_id, _)) = state.vfs.read().0.file_id(&path) {
             state.diagnostics.clear_native_for(file_id);
         }
 
@@ -146,7 +156,7 @@ pub(crate) fn handle_did_save_text_document(
 ) -> anyhow::Result<()> {
     if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
         let snap = state.snapshot();
-        let file_id = snap.vfs_path_to_file_id(&vfs_path)?;
+        let file_id = try_default!(snap.vfs_path_to_file_id(&vfs_path)?);
         let sr = snap.analysis.source_root_id(file_id)?;
 
         if state.config.script_rebuild_on_save(Some(sr)) && state.build_deps_changed {
@@ -290,7 +300,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
     let _p = tracing::info_span!("run_flycheck").entered();
 
     let file_id = state.vfs.read().0.file_id(&vfs_path);
-    if let Some(file_id) = file_id {
+    if let Some((file_id, vfs::FileExcluded::No)) = file_id {
         let world = state.snapshot();
         let invocation_strategy_once = state.config.flycheck(None).invocation_strategy_once();
         let may_flycheck_workspace = state.config.flycheck_workspace(None);
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 ed028f1d37b..1b144d90732 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
@@ -53,6 +53,7 @@ use crate::{
     },
     target_spec::{CargoTargetSpec, TargetSpec},
     test_runner::{CargoTestHandle, TestTarget},
+    try_default,
 };
 
 pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
@@ -83,7 +84,8 @@ pub(crate) fn handle_analyzer_status(
     let mut file_id = None;
     if let Some(tdi) = params.text_document {
         match from_proto::file_id(&snap, &tdi.uri) {
-            Ok(it) => file_id = Some(it),
+            Ok(Some(it)) => file_id = Some(it),
+            Ok(None) => {}
             Err(_) => format_to!(buf, "file {} not found in vfs", tdi.uri),
         }
     }
@@ -141,7 +143,7 @@ pub(crate) fn handle_view_syntax_tree(
     params: lsp_ext::ViewSyntaxTreeParams,
 ) -> anyhow::Result<String> {
     let _p = tracing::info_span!("handle_view_syntax_tree").entered();
-    let id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let res = snap.analysis.view_syntax_tree(id)?;
     Ok(res)
 }
@@ -151,7 +153,7 @@ pub(crate) fn handle_view_hir(
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<String> {
     let _p = tracing::info_span!("handle_view_hir").entered();
-    let position = from_proto::file_position(&snap, params)?;
+    let position = try_default!(from_proto::file_position(&snap, params)?);
     let res = snap.analysis.view_hir(position)?;
     Ok(res)
 }
@@ -161,7 +163,7 @@ pub(crate) fn handle_view_mir(
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<String> {
     let _p = tracing::info_span!("handle_view_mir").entered();
-    let position = from_proto::file_position(&snap, params)?;
+    let position = try_default!(from_proto::file_position(&snap, params)?);
     let res = snap.analysis.view_mir(position)?;
     Ok(res)
 }
@@ -171,7 +173,7 @@ pub(crate) fn handle_interpret_function(
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<String> {
     let _p = tracing::info_span!("handle_interpret_function").entered();
-    let position = from_proto::file_position(&snap, params)?;
+    let position = try_default!(from_proto::file_position(&snap, params)?);
     let res = snap.analysis.interpret_function(position)?;
     Ok(res)
 }
@@ -180,7 +182,7 @@ pub(crate) fn handle_view_file_text(
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentIdentifier,
 ) -> anyhow::Result<String> {
-    let file_id = from_proto::file_id(&snap, &params.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.uri)?);
     Ok(snap.analysis.file_text(file_id)?.to_string())
 }
 
@@ -189,7 +191,7 @@ pub(crate) fn handle_view_item_tree(
     params: lsp_ext::ViewItemTreeParams,
 ) -> anyhow::Result<String> {
     let _p = tracing::info_span!("handle_view_item_tree").entered();
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let res = snap.analysis.view_item_tree(file_id)?;
     Ok(res)
 }
@@ -315,7 +317,7 @@ pub(crate) fn handle_expand_macro(
     params: lsp_ext::ExpandMacroParams,
 ) -> anyhow::Result<Option<lsp_ext::ExpandedMacro>> {
     let _p = tracing::info_span!("handle_expand_macro").entered();
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let line_index = snap.file_line_index(file_id)?;
     let offset = from_proto::offset(&line_index, params.position)?;
 
@@ -328,7 +330,7 @@ pub(crate) fn handle_selection_range(
     params: lsp_types::SelectionRangeParams,
 ) -> anyhow::Result<Option<Vec<lsp_types::SelectionRange>>> {
     let _p = tracing::info_span!("handle_selection_range").entered();
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let line_index = snap.file_line_index(file_id)?;
     let res: anyhow::Result<Vec<lsp_types::SelectionRange>> = params
         .positions
@@ -371,7 +373,7 @@ pub(crate) fn handle_matching_brace(
     params: lsp_ext::MatchingBraceParams,
 ) -> anyhow::Result<Vec<Position>> {
     let _p = tracing::info_span!("handle_matching_brace").entered();
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let line_index = snap.file_line_index(file_id)?;
     params
         .positions
@@ -395,7 +397,7 @@ pub(crate) fn handle_join_lines(
 ) -> anyhow::Result<Vec<lsp_types::TextEdit>> {
     let _p = tracing::info_span!("handle_join_lines").entered();
 
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let config = snap.config.join_lines();
     let line_index = snap.file_line_index(file_id)?;
 
@@ -419,7 +421,7 @@ pub(crate) fn handle_on_enter(
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
     let _p = tracing::info_span!("handle_on_enter").entered();
-    let position = from_proto::file_position(&snap, params)?;
+    let position = try_default!(from_proto::file_position(&snap, params)?);
     let edit = match snap.analysis.on_enter(position)? {
         None => return Ok(None),
         Some(it) => it,
@@ -439,7 +441,8 @@ pub(crate) fn handle_on_type_formatting(
         return Ok(None);
     }
 
-    let mut position = from_proto::file_position(&snap, params.text_document_position)?;
+    let mut position =
+        try_default!(from_proto::file_position(&snap, params.text_document_position)?);
     let line_index = snap.file_line_index(position.file_id)?;
 
     // in `ide`, the `on_type` invariant is that
@@ -465,32 +468,33 @@ pub(crate) fn handle_on_type_formatting(
     Ok(Some(change))
 }
 
+pub(crate) fn empty_diagnostic_report() -> lsp_types::DocumentDiagnosticReportResult {
+    lsp_types::DocumentDiagnosticReportResult::Report(lsp_types::DocumentDiagnosticReport::Full(
+        lsp_types::RelatedFullDocumentDiagnosticReport {
+            related_documents: None,
+            full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
+                result_id: Some("rust-analyzer".to_owned()),
+                items: vec![],
+            },
+        },
+    ))
+}
+
 pub(crate) fn handle_document_diagnostics(
     snap: GlobalStateSnapshot,
     params: lsp_types::DocumentDiagnosticParams,
 ) -> anyhow::Result<lsp_types::DocumentDiagnosticReportResult> {
-    let empty = || {
-        lsp_types::DocumentDiagnosticReportResult::Report(
-            lsp_types::DocumentDiagnosticReport::Full(
-                lsp_types::RelatedFullDocumentDiagnosticReport {
-                    related_documents: None,
-                    full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
-                        result_id: Some("rust-analyzer".to_owned()),
-                        items: vec![],
-                    },
-                },
-            ),
-        )
+    let file_id = match from_proto::file_id(&snap, &params.text_document.uri)? {
+        Some(it) => it,
+        None => return Ok(empty_diagnostic_report()),
     };
-
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
     let source_root = snap.analysis.source_root_id(file_id)?;
     if !snap.analysis.is_local_source_root(source_root)? {
-        return Ok(empty());
+        return Ok(empty_diagnostic_report());
     }
     let config = snap.config.diagnostics(Some(source_root));
     if !config.enabled {
-        return Ok(empty());
+        return Ok(empty_diagnostic_report());
     }
     let line_index = snap.file_line_index(file_id)?;
     let supports_related = snap.config.text_document_diagnostic_related_document_support();
@@ -546,7 +550,7 @@ pub(crate) fn handle_document_symbol(
     params: lsp_types::DocumentSymbolParams,
 ) -> anyhow::Result<Option<lsp_types::DocumentSymbolResponse>> {
     let _p = tracing::info_span!("handle_document_symbol").entered();
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let line_index = snap.file_line_index(file_id)?;
 
     let mut parents: Vec<(lsp_types::DocumentSymbol, Option<usize>)> = Vec::new();
@@ -760,7 +764,7 @@ pub(crate) fn handle_will_rename_files(
             }
         })
         .filter_map(|(file_id, new_name)| {
-            snap.analysis.will_rename_file(file_id, &new_name).ok()?
+            snap.analysis.will_rename_file(file_id?, &new_name).ok()?
         })
         .collect();
 
@@ -782,7 +786,8 @@ pub(crate) fn handle_goto_definition(
     params: lsp_types::GotoDefinitionParams,
 ) -> anyhow::Result<Option<lsp_types::GotoDefinitionResponse>> {
     let _p = tracing::info_span!("handle_goto_definition").entered();
-    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
+    let position =
+        try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
     let nav_info = match snap.analysis.goto_definition(position)? {
         None => return Ok(None),
         Some(it) => it,
@@ -797,7 +802,10 @@ pub(crate) fn handle_goto_declaration(
     params: lsp_types::request::GotoDeclarationParams,
 ) -> anyhow::Result<Option<lsp_types::request::GotoDeclarationResponse>> {
     let _p = tracing::info_span!("handle_goto_declaration").entered();
-    let position = from_proto::file_position(&snap, params.text_document_position_params.clone())?;
+    let position = try_default!(from_proto::file_position(
+        &snap,
+        params.text_document_position_params.clone()
+    )?);
     let nav_info = match snap.analysis.goto_declaration(position)? {
         None => return handle_goto_definition(snap, params),
         Some(it) => it,
@@ -812,7 +820,8 @@ pub(crate) fn handle_goto_implementation(
     params: lsp_types::request::GotoImplementationParams,
 ) -> anyhow::Result<Option<lsp_types::request::GotoImplementationResponse>> {
     let _p = tracing::info_span!("handle_goto_implementation").entered();
-    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
+    let position =
+        try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
     let nav_info = match snap.analysis.goto_implementation(position)? {
         None => return Ok(None),
         Some(it) => it,
@@ -827,7 +836,8 @@ pub(crate) fn handle_goto_type_definition(
     params: lsp_types::request::GotoTypeDefinitionParams,
 ) -> anyhow::Result<Option<lsp_types::request::GotoTypeDefinitionResponse>> {
     let _p = tracing::info_span!("handle_goto_type_definition").entered();
-    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
+    let position =
+        try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
     let nav_info = match snap.analysis.goto_type_definition(position)? {
         None => return Ok(None),
         Some(it) => it,
@@ -880,7 +890,7 @@ pub(crate) fn handle_parent_module(
         }
 
         // check if invoked at the crate root
-        let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+        let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
         let crate_id = match snap.analysis.crates_for(file_id)?.first() {
             Some(&crate_id) => crate_id,
             None => return Ok(None),
@@ -904,7 +914,7 @@ pub(crate) fn handle_parent_module(
     }
 
     // locate parent module by semantics
-    let position = from_proto::file_position(&snap, params)?;
+    let position = try_default!(from_proto::file_position(&snap, params)?);
     let navs = snap.analysis.parent_module(position)?;
     let res = to_proto::goto_definition_response(&snap, None, navs)?;
     Ok(Some(res))
@@ -915,7 +925,7 @@ pub(crate) fn handle_runnables(
     params: lsp_ext::RunnablesParams,
 ) -> anyhow::Result<Vec<lsp_ext::Runnable>> {
     let _p = tracing::info_span!("handle_runnables").entered();
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let source_root = snap.analysis.source_root_id(file_id).ok();
     let line_index = snap.file_line_index(file_id)?;
     let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok());
@@ -1035,7 +1045,7 @@ pub(crate) fn handle_related_tests(
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<Vec<lsp_ext::TestInfo>> {
     let _p = tracing::info_span!("handle_related_tests").entered();
-    let position = from_proto::file_position(&snap, params)?;
+    let position = try_default!(from_proto::file_position(&snap, params)?);
 
     let tests = snap.analysis.related_tests(position, None)?;
     let mut res = Vec::new();
@@ -1053,7 +1063,8 @@ pub(crate) fn handle_completion(
     lsp_types::CompletionParams { text_document_position, context,.. }: lsp_types::CompletionParams,
 ) -> anyhow::Result<Option<lsp_types::CompletionResponse>> {
     let _p = tracing::info_span!("handle_completion").entered();
-    let mut position = from_proto::file_position(&snap, text_document_position.clone())?;
+    let mut position =
+        try_default!(from_proto::file_position(&snap, text_document_position.clone())?);
     let line_index = snap.file_line_index(position.file_id)?;
     let completion_trigger_character =
         context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
@@ -1102,7 +1113,8 @@ pub(crate) fn handle_completion_resolve(
 
     let resolve_data: lsp_ext::CompletionResolveData = serde_json::from_value(data)?;
 
-    let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
+    let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?
+        .expect("we never provide completions for excluded files");
     let line_index = snap.file_line_index(file_id)?;
     // FIXME: We should fix up the position when retrying the cancelled request instead
     let Ok(offset) = from_proto::offset(&line_index, resolve_data.position.position) else {
@@ -1185,7 +1197,7 @@ pub(crate) fn handle_folding_range(
     params: FoldingRangeParams,
 ) -> anyhow::Result<Option<Vec<FoldingRange>>> {
     let _p = tracing::info_span!("handle_folding_range").entered();
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let folds = snap.analysis.folding_ranges(file_id)?;
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
@@ -1202,7 +1214,8 @@ pub(crate) fn handle_signature_help(
     params: lsp_types::SignatureHelpParams,
 ) -> anyhow::Result<Option<lsp_types::SignatureHelp>> {
     let _p = tracing::info_span!("handle_signature_help").entered();
-    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
+    let position =
+        try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
     let help = match snap.analysis.signature_help(position)? {
         Some(it) => it,
         None => return Ok(None),
@@ -1221,7 +1234,7 @@ pub(crate) fn handle_hover(
         PositionOrRange::Position(position) => Range::new(position, position),
         PositionOrRange::Range(range) => range,
     };
-    let file_range = from_proto::file_range(&snap, &params.text_document, range)?;
+    let file_range = try_default!(from_proto::file_range(&snap, &params.text_document, range)?);
 
     let hover = snap.config.hover();
     let info = match snap.analysis.hover(&hover, file_range)? {
@@ -1255,7 +1268,7 @@ pub(crate) fn handle_prepare_rename(
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<Option<PrepareRenameResponse>> {
     let _p = tracing::info_span!("handle_prepare_rename").entered();
-    let position = from_proto::file_position(&snap, params)?;
+    let position = try_default!(from_proto::file_position(&snap, params)?);
 
     let change = snap.analysis.prepare_rename(position)?.map_err(to_proto::rename_error)?;
 
@@ -1269,7 +1282,7 @@ pub(crate) fn handle_rename(
     params: RenameParams,
 ) -> anyhow::Result<Option<WorkspaceEdit>> {
     let _p = tracing::info_span!("handle_rename").entered();
-    let position = from_proto::file_position(&snap, params.text_document_position)?;
+    let position = try_default!(from_proto::file_position(&snap, params.text_document_position)?);
 
     let mut change =
         snap.analysis.rename(position, &params.new_name)?.map_err(to_proto::rename_error)?;
@@ -1304,7 +1317,7 @@ pub(crate) fn handle_references(
     params: lsp_types::ReferenceParams,
 ) -> anyhow::Result<Option<Vec<Location>>> {
     let _p = tracing::info_span!("handle_references").entered();
-    let position = from_proto::file_position(&snap, params.text_document_position)?;
+    let position = try_default!(from_proto::file_position(&snap, params.text_document_position)?);
 
     let exclude_imports = snap.config.find_all_refs_exclude_imports();
     let exclude_tests = snap.config.find_all_refs_exclude_tests();
@@ -1375,9 +1388,9 @@ pub(crate) fn handle_code_action(
         return Ok(None);
     }
 
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let line_index = snap.file_line_index(file_id)?;
-    let frange = from_proto::file_range(&snap, &params.text_document, params.range)?;
+    let frange = try_default!(from_proto::file_range(&snap, &params.text_document, params.range)?);
     let source_root = snap.analysis.source_root_id(file_id)?;
 
     let mut assists_config = snap.config.assist(Some(source_root));
@@ -1455,7 +1468,8 @@ pub(crate) fn handle_code_action_resolve(
         return Err(invalid_params_error("code action without data".to_owned()).into());
     };
 
-    let file_id = from_proto::file_id(&snap, &params.code_action_params.text_document.uri)?;
+    let file_id = from_proto::file_id(&snap, &params.code_action_params.text_document.uri)?
+        .expect("we never provide code actions for excluded files");
     if snap.file_version(file_id) != params.version {
         return Err(invalid_params_error("stale code action".to_owned()).into());
     }
@@ -1551,7 +1565,7 @@ pub(crate) fn handle_code_lens(
         return Ok(Some(Vec::default()));
     }
 
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let target_spec = TargetSpec::for_file(&snap, file_id)?;
 
     let annotations = snap.analysis.annotations(
@@ -1613,7 +1627,8 @@ pub(crate) fn handle_document_highlight(
     params: lsp_types::DocumentHighlightParams,
 ) -> anyhow::Result<Option<Vec<lsp_types::DocumentHighlight>>> {
     let _p = tracing::info_span!("handle_document_highlight").entered();
-    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
+    let position =
+        try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
     let line_index = snap.file_line_index(position.file_id)?;
     let source_root = snap.analysis.source_root_id(position.file_id)?;
 
@@ -1639,12 +1654,12 @@ pub(crate) fn handle_ssr(
     params: lsp_ext::SsrParams,
 ) -> anyhow::Result<lsp_types::WorkspaceEdit> {
     let _p = tracing::info_span!("handle_ssr").entered();
-    let selections = params
+    let selections = try_default!(params
         .selections
         .iter()
         .map(|range| from_proto::file_range(&snap, &params.position.text_document, *range))
-        .collect::<Result<Vec<_>, _>>()?;
-    let position = from_proto::file_position(&snap, params.position)?;
+        .collect::<Result<Option<Vec<_>>, _>>()?);
+    let position = try_default!(from_proto::file_position(&snap, params.position)?);
     let source_change = snap.analysis.structural_search_replace(
         &params.query,
         params.parse_only,
@@ -1660,11 +1675,11 @@ pub(crate) fn handle_inlay_hints(
 ) -> anyhow::Result<Option<Vec<InlayHint>>> {
     let _p = tracing::info_span!("handle_inlay_hints").entered();
     let document_uri = &params.text_document.uri;
-    let FileRange { file_id, range } = from_proto::file_range(
+    let FileRange { file_id, range } = try_default!(from_proto::file_range(
         &snap,
         &TextDocumentIdentifier::new(document_uri.to_owned()),
         params.range,
-    )?;
+    )?);
     let line_index = snap.file_line_index(file_id)?;
     let range = TextRange::new(
         range.start().min(line_index.index.len()),
@@ -1744,7 +1759,8 @@ pub(crate) fn handle_call_hierarchy_prepare(
     params: CallHierarchyPrepareParams,
 ) -> anyhow::Result<Option<Vec<CallHierarchyItem>>> {
     let _p = tracing::info_span!("handle_call_hierarchy_prepare").entered();
-    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
+    let position =
+        try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
 
     let nav_info = match snap.analysis.call_hierarchy(position)? {
         None => return Ok(None),
@@ -1769,7 +1785,7 @@ pub(crate) fn handle_call_hierarchy_incoming(
     let item = params.item;
 
     let doc = TextDocumentIdentifier::new(item.uri);
-    let frange = from_proto::file_range(&snap, &doc, item.selection_range)?;
+    let frange = try_default!(from_proto::file_range(&snap, &doc, item.selection_range)?);
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 
     let config = snap.config.call_hierarchy();
@@ -1807,7 +1823,7 @@ pub(crate) fn handle_call_hierarchy_outgoing(
     let item = params.item;
 
     let doc = TextDocumentIdentifier::new(item.uri);
-    let frange = from_proto::file_range(&snap, &doc, item.selection_range)?;
+    let frange = try_default!(from_proto::file_range(&snap, &doc, item.selection_range)?);
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
     let line_index = snap.file_line_index(fpos.file_id)?;
 
@@ -1842,7 +1858,7 @@ pub(crate) fn handle_semantic_tokens_full(
 ) -> anyhow::Result<Option<SemanticTokensResult>> {
     let _p = tracing::info_span!("handle_semantic_tokens_full").entered();
 
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
@@ -1872,7 +1888,7 @@ pub(crate) fn handle_semantic_tokens_full_delta(
 ) -> anyhow::Result<Option<SemanticTokensFullDeltaResult>> {
     let _p = tracing::info_span!("handle_semantic_tokens_full_delta").entered();
 
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
@@ -1915,7 +1931,7 @@ pub(crate) fn handle_semantic_tokens_range(
 ) -> anyhow::Result<Option<SemanticTokensRangeResult>> {
     let _p = tracing::info_span!("handle_semantic_tokens_range").entered();
 
-    let frange = from_proto::file_range(&snap, &params.text_document, params.range)?;
+    let frange = try_default!(from_proto::file_range(&snap, &params.text_document, params.range)?);
     let text = snap.analysis.file_text(frange.file_id)?;
     let line_index = snap.file_line_index(frange.file_id)?;
 
@@ -1940,7 +1956,7 @@ pub(crate) fn handle_open_docs(
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<ExternalDocsResponse> {
     let _p = tracing::info_span!("handle_open_docs").entered();
-    let position = from_proto::file_position(&snap, params)?;
+    let position = try_default!(from_proto::file_position(&snap, params)?);
 
     let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match &ws.kind {
         ProjectWorkspaceKind::Cargo { cargo, .. }
@@ -1982,7 +1998,7 @@ pub(crate) fn handle_open_cargo_toml(
     params: lsp_ext::OpenCargoTomlParams,
 ) -> anyhow::Result<Option<lsp_types::GotoDefinitionResponse>> {
     let _p = tracing::info_span!("handle_open_cargo_toml").entered();
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
 
     let cargo_spec = match TargetSpec::for_file(&snap, file_id)? {
         Some(TargetSpec::Cargo(it)) => it,
@@ -2000,8 +2016,8 @@ pub(crate) fn handle_move_item(
     params: lsp_ext::MoveItemParams,
 ) -> anyhow::Result<Vec<lsp_ext::SnippetTextEdit>> {
     let _p = tracing::info_span!("handle_move_item").entered();
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
-    let range = from_proto::file_range(&snap, &params.text_document, params.range)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
+    let range = try_default!(from_proto::file_range(&snap, &params.text_document, params.range)?);
 
     let direction = match params.direction {
         lsp_ext::MoveItemDirection::Up => ide::Direction::Up,
@@ -2022,7 +2038,7 @@ pub(crate) fn handle_view_recursive_memory_layout(
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<Option<lsp_ext::RecursiveMemoryLayout>> {
     let _p = tracing::info_span!("handle_view_recursive_memory_layout").entered();
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
     let line_index = snap.file_line_index(file_id)?;
     let offset = from_proto::offset(&line_index, params.position)?;
 
@@ -2210,7 +2226,7 @@ fn run_rustfmt(
     text_document: TextDocumentIdentifier,
     range: Option<lsp_types::Range>,
 ) -> anyhow::Result<Option<Vec<lsp_types::TextEdit>>> {
-    let file_id = from_proto::file_id(snap, &text_document.uri)?;
+    let file_id = try_default!(from_proto::file_id(snap, &text_document.uri)?);
     let file = snap.analysis.file_text(file_id)?;
 
     // Determine the edition of the crate the file belongs to (if there's multiple, we pick the
@@ -2275,7 +2291,7 @@ fn run_rustfmt(
                     .into());
                 }
 
-                let frange = from_proto::file_range(snap, &text_document, range)?;
+                let frange = try_default!(from_proto::file_range(snap, &text_document, range)?);
                 let start_line = line_index.index.line_col(frange.range.start()).line;
                 let end_line = line_index.index.line_col(frange.range.end()).line;
 
@@ -2284,7 +2300,8 @@ fn run_rustfmt(
                 cmd.arg(
                     json!([{
                         "file": "stdin",
-                        "range": [start_line, end_line]
+                        // LineCol is 0-based, but rustfmt is 1-based.
+                        "range": [start_line + 1, end_line + 1]
                     }])
                     .to_string(),
                 );
@@ -2416,15 +2433,15 @@ pub(crate) fn internal_testing_fetch_config(
     state: GlobalStateSnapshot,
     params: InternalTestingFetchConfigParams,
 ) -> anyhow::Result<Option<InternalTestingFetchConfigResponse>> {
-    let source_root = params
-        .text_document
-        .map(|it| {
+    let source_root = match params.text_document {
+        Some(it) => Some(
             state
                 .analysis
-                .source_root_id(from_proto::file_id(&state, &it.uri)?)
-                .map_err(anyhow::Error::from)
-        })
-        .transpose()?;
+                .source_root_id(try_default!(from_proto::file_id(&state, &it.uri)?))
+                .map_err(anyhow::Error::from)?,
+        ),
+        None => None,
+    };
     Ok(Some(match params.config {
         InternalTestingFetchConfigOption::AssistEmitMustUse => {
             InternalTestingFetchConfigResponse::AssistEmitMustUse(
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
index 5cdc51a1c19..c6aa8ba1707 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -25,6 +25,14 @@ use vfs::{AbsPathBuf, VfsPath};
 
 use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice};
 
+#[track_caller]
+fn file_id(vfs: &vfs::Vfs, path: &VfsPath) -> vfs::FileId {
+    match vfs.file_id(path) {
+        Some((file_id, vfs::FileExcluded::No)) => file_id,
+        None | Some((_, vfs::FileExcluded::Yes)) => panic!("can't find virtual file for {path}"),
+    }
+}
+
 #[test]
 fn integrated_highlighting_benchmark() {
     if std::env::var("RUN_SLOW_BENCHES").is_err() {
@@ -62,7 +70,7 @@ fn integrated_highlighting_benchmark() {
     let file_id = {
         let file = workspace_to_load.join(file);
         let path = VfsPath::from(AbsPathBuf::assert(file));
-        vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}"))
+        file_id(&vfs, &path)
     };
 
     {
@@ -130,7 +138,7 @@ fn integrated_completion_benchmark() {
     let file_id = {
         let file = workspace_to_load.join(file);
         let path = VfsPath::from(AbsPathBuf::assert(file));
-        vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}"))
+        file_id(&vfs, &path)
     };
 
     // kick off parsing and index population
@@ -324,7 +332,7 @@ fn integrated_diagnostics_benchmark() {
     let file_id = {
         let file = workspace_to_load.join(file);
         let path = VfsPath::from(AbsPathBuf::assert(file));
-        vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}"))
+        file_id(&vfs, &path)
     };
 
     let diagnostics_config = DiagnosticsConfig {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index 1221f7c7012..27d6225cdb7 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -173,3 +173,14 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
 
     hasher.finalize()
 }
+
+#[doc(hidden)]
+macro_rules! try_default_ {
+    ($it:expr $(,)?) => {
+        match $it {
+            Some(it) => it,
+            None => return Ok(Default::default()),
+        }
+    };
+}
+pub(crate) use try_default_ as try_default;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
index 47e9961cf13..6375a1a054b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
@@ -9,7 +9,7 @@ use vfs::AbsPathBuf;
 use crate::{
     global_state::GlobalStateSnapshot,
     line_index::{LineIndex, PositionEncoding},
-    lsp_ext,
+    lsp_ext, try_default,
 };
 
 pub(crate) fn abs_path(url: &lsp_types::Url) -> anyhow::Result<AbsPathBuf> {
@@ -61,37 +61,44 @@ pub(crate) fn text_range(
     }
 }
 
-pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> anyhow::Result<FileId> {
+/// Returns `None` if the file was excluded.
+pub(crate) fn file_id(
+    snap: &GlobalStateSnapshot,
+    url: &lsp_types::Url,
+) -> anyhow::Result<Option<FileId>> {
     snap.url_to_file_id(url)
 }
 
+/// Returns `None` if the file was excluded.
 pub(crate) fn file_position(
     snap: &GlobalStateSnapshot,
     tdpp: lsp_types::TextDocumentPositionParams,
-) -> anyhow::Result<FilePosition> {
-    let file_id = file_id(snap, &tdpp.text_document.uri)?;
+) -> anyhow::Result<Option<FilePosition>> {
+    let file_id = try_default!(file_id(snap, &tdpp.text_document.uri)?);
     let line_index = snap.file_line_index(file_id)?;
     let offset = offset(&line_index, tdpp.position)?;
-    Ok(FilePosition { file_id, offset })
+    Ok(Some(FilePosition { file_id, offset }))
 }
 
+/// Returns `None` if the file was excluded.
 pub(crate) fn file_range(
     snap: &GlobalStateSnapshot,
     text_document_identifier: &lsp_types::TextDocumentIdentifier,
     range: lsp_types::Range,
-) -> anyhow::Result<FileRange> {
+) -> anyhow::Result<Option<FileRange>> {
     file_range_uri(snap, &text_document_identifier.uri, range)
 }
 
+/// Returns `None` if the file was excluded.
 pub(crate) fn file_range_uri(
     snap: &GlobalStateSnapshot,
     document: &lsp_types::Url,
     range: lsp_types::Range,
-) -> anyhow::Result<FileRange> {
-    let file_id = file_id(snap, document)?;
+) -> anyhow::Result<Option<FileRange>> {
+    let file_id = try_default!(file_id(snap, document)?);
     let line_index = snap.file_line_index(file_id)?;
     let range = text_range(&line_index, range)?;
-    Ok(FileRange { file_id, range })
+    Ok(Some(FileRange { file_id, range }))
 }
 
 pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind> {
@@ -108,6 +115,7 @@ pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind>
     Some(assist_kind)
 }
 
+/// Returns `None` if the file was excluded.
 pub(crate) fn annotation(
     snap: &GlobalStateSnapshot,
     range: lsp_types::Range,
@@ -121,7 +129,7 @@ pub(crate) fn annotation(
                 return Ok(None);
             }
             let pos @ FilePosition { file_id, .. } =
-                file_position(snap, params.text_document_position_params)?;
+                try_default!(file_position(snap, params.text_document_position_params)?);
             let line_index = snap.file_line_index(file_id)?;
 
             Ok(Annotation {
@@ -133,7 +141,7 @@ pub(crate) fn annotation(
             if snap.url_file_version(&params.text_document.uri) != Some(data.version) {
                 return Ok(None);
             }
-            let pos @ FilePosition { file_id, .. } = file_position(snap, params)?;
+            let pos @ FilePosition { file_id, .. } = try_default!(file_position(snap, params)?);
             let line_index = snap.file_line_index(file_id)?;
 
             Ok(Annotation {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index ebc65373b52..f5d9469f262 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -27,7 +27,10 @@ use crate::{
         FetchWorkspaceResponse, GlobalState,
     },
     hack_recover_crate_name,
-    handlers::dispatch::{NotificationDispatcher, RequestDispatcher},
+    handlers::{
+        dispatch::{NotificationDispatcher, RequestDispatcher},
+        request::empty_diagnostic_report,
+    },
     lsp::{
         from_proto, to_proto,
         utils::{notification_is, Progress},
@@ -548,6 +551,9 @@ impl GlobalState {
             self.mem_docs
                 .iter()
                 .map(|path| vfs.file_id(path).unwrap())
+                .filter_map(|(file_id, excluded)| {
+                    (excluded == vfs::FileExcluded::No).then_some(file_id)
+                })
                 .filter(|&file_id| {
                     let source_root = db.file_source_root(file_id);
                     // Only publish diagnostics for files in the workspace, not from crates.io deps
@@ -632,6 +638,9 @@ impl GlobalState {
             .mem_docs
             .iter()
             .map(|path| self.vfs.read().0.file_id(path).unwrap())
+            .filter_map(|(file_id, excluded)| {
+                (excluded == vfs::FileExcluded::No).then_some(file_id)
+            })
             .filter(|&file_id| {
                 let source_root = db.file_source_root(file_id);
                 !db.source_root(source_root).is_library
@@ -879,7 +888,10 @@ impl GlobalState {
                 self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
                     let _p = tracing::info_span!("GlobalState::check_if_indexed").entered();
                     tracing::debug!(?uri, "handling uri");
-                    let id = from_proto::file_id(&snap, &uri).expect("unable to get FileId");
+                    let Some(id) = from_proto::file_id(&snap, &uri).expect("unable to get FileId")
+                    else {
+                        return;
+                    };
                     if let Ok(crates) = &snap.analysis.crates_for(id) {
                         if crates.is_empty() {
                             if snap.config.discover_workspace_config().is_some() {
@@ -987,13 +999,14 @@ impl GlobalState {
                 );
                 for diag in diagnostics {
                     match url_to_file_id(&self.vfs.read().0, &diag.url) {
-                        Ok(file_id) => self.diagnostics.add_check_diagnostic(
+                        Ok(Some(file_id)) => self.diagnostics.add_check_diagnostic(
                             id,
                             &package_id,
                             file_id,
                             diag.diagnostic,
                             diag.fix,
                         ),
+                        Ok(None) => {}
                         Err(err) => {
                             error!(
                                 "flycheck {id}: File with cargo diagnostic not found in VFS: {}",
@@ -1115,17 +1128,7 @@ impl GlobalState {
             .on_latency_sensitive::<NO_RETRY, lsp_request::SemanticTokensRangeRequest>(handlers::handle_semantic_tokens_range)
             // FIXME: Some of these NO_RETRY could be retries if the file they are interested didn't change.
             // All other request handlers
-            .on_with_vfs_default::<lsp_request::DocumentDiagnosticRequest>(handlers::handle_document_diagnostics, || lsp_types::DocumentDiagnosticReportResult::Report(
-                lsp_types::DocumentDiagnosticReport::Full(
-                    lsp_types::RelatedFullDocumentDiagnosticReport {
-                        related_documents: None,
-                        full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
-                            result_id: Some("rust-analyzer".to_owned()),
-                            items: vec![],
-                        },
-                    },
-                ),
-            ), || lsp_server::ResponseError {
+            .on_with_vfs_default::<lsp_request::DocumentDiagnosticRequest>(handlers::handle_document_diagnostics, empty_diagnostic_report, || lsp_server::ResponseError {
                 code: lsp_server::ErrorCode::ServerCancelled as i32,
                 message: "server cancelled the request".to_owned(),
                 data: serde_json::to_value(lsp_types::DiagnosticServerCancellationData {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index d18e5770477..ba72ea35df6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -316,6 +316,7 @@ impl GlobalState {
                             let workspace = project_model::ProjectWorkspace::load_inline(
                                 it.clone(),
                                 &cargo_config,
+                                &progress,
                             );
                             Ok(workspace)
                         }
@@ -705,7 +706,9 @@ impl GlobalState {
             let load = |path: &AbsPath| {
                 let vfs_path = vfs::VfsPath::from(path.to_path_buf());
                 self.crate_graph_file_dependencies.insert(vfs_path.clone());
-                vfs.file_id(&vfs_path)
+                vfs.file_id(&vfs_path).and_then(|(file_id, excluded)| {
+                    (excluded == vfs::FileExcluded::No).then_some(file_id)
+                })
             };
 
             ws_to_crate_graph(&self.workspaces, self.config.extra_env(None), load)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index 2b3c0a47a22..6f26bdc2cf0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -21,12 +21,14 @@ use lsp_types::{
     notification::DidOpenTextDocument,
     request::{
         CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest,
-        InlayHintRequest, InlayHintResolveRequest, WillRenameFiles, WorkspaceSymbolRequest,
+        InlayHintRequest, InlayHintResolveRequest, RangeFormatting, WillRenameFiles,
+        WorkspaceSymbolRequest,
     },
     CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams,
-    DocumentFormattingParams, FileRename, FormattingOptions, GotoDefinitionParams, HoverParams,
-    InlayHint, InlayHintLabel, InlayHintParams, PartialResultParams, Position, Range,
-    RenameFilesParams, TextDocumentItem, TextDocumentPositionParams, WorkDoneProgressParams,
+    DocumentFormattingParams, DocumentRangeFormattingParams, FileRename, FormattingOptions,
+    GotoDefinitionParams, HoverParams, InlayHint, InlayHintLabel, InlayHintParams,
+    PartialResultParams, Position, Range, RenameFilesParams, TextDocumentItem,
+    TextDocumentPositionParams, WorkDoneProgressParams,
 };
 use rust_analyzer::lsp::ext::{OnEnter, Runnables, RunnablesParams};
 use serde_json::json;
@@ -661,6 +663,70 @@ fn main() {}
 }
 
 #[test]
+fn test_format_document_range() {
+    if skip_slow_tests() {
+        return;
+    }
+
+    let server = Project::with_fixture(
+        r#"
+//- /Cargo.toml
+[package]
+name = "foo"
+version = "0.0.0"
+
+//- /src/lib.rs
+fn main() {
+    let unit_offsets_cache = collect(dwarf.units  ())  ?;
+}
+"#,
+    )
+    .with_config(serde_json::json!({
+        "rustfmt": {
+            "overrideCommand": [ "rustfmt", "+nightly", ],
+            "rangeFormatting": { "enable": true }
+        },
+    }))
+    .server()
+    .wait_until_workspace_is_loaded();
+
+    server.request::<RangeFormatting>(
+        DocumentRangeFormattingParams {
+            range: Range {
+                end: Position { line: 1, character: 0 },
+                start: Position { line: 1, character: 0 },
+            },
+            text_document: server.doc_id("src/lib.rs"),
+            options: FormattingOptions {
+                tab_size: 4,
+                insert_spaces: false,
+                insert_final_newline: None,
+                trim_final_newlines: None,
+                trim_trailing_whitespace: None,
+                properties: HashMap::new(),
+            },
+            work_done_progress_params: WorkDoneProgressParams::default(),
+        },
+        json!([
+            {
+                "newText": "",
+                "range": {
+                    "start": { "character": 48, "line": 1 },
+                    "end": { "character": 50, "line": 1 },
+                },
+            },
+            {
+                "newText": "",
+                "range": {
+                    "start": { "character": 53, "line": 1 },
+                    "end": { "character": 55, "line": 1 },
+                },
+            }
+        ]),
+    );
+}
+
+#[test]
 fn test_missing_module_code_action() {
     if skip_slow_tests() {
         return;
@@ -1086,7 +1152,11 @@ fn resolve_proc_macro() {
         &AbsPathBuf::assert_utf8(std::env::current_dir().unwrap()),
         &Default::default(),
     );
-    sysroot.load_workspace(&project_model::SysrootSourceWorkspaceConfig::default_cargo());
+    let loaded_sysroot =
+        sysroot.load_workspace(&project_model::RustSourceWorkspaceConfig::default_cargo());
+    if let Some(loaded_sysroot) = loaded_sysroot {
+        sysroot.set_workspace(loaded_sysroot);
+    }
 
     let proc_macro_server_path = sysroot.discover_proc_macro_srv().unwrap();
 
@@ -1372,6 +1442,40 @@ pub fn foo() {}
 name = "bar"
 version = "0.0.0"
 
+[dependencies]
+foo = { path = "../foo" }
+
+//- /bar/src/lib.rs
+"#,
+    )
+    .root("foo")
+    .root("bar")
+    .root("baz")
+    .with_config(json!({
+       "files": {
+           "exclude": ["foo"]
+        }
+    }))
+    .server()
+    .wait_until_workspace_is_loaded();
+
+    server.request::<WorkspaceSymbolRequest>(Default::default(), json!([]));
+
+    let server = Project::with_fixture(
+        r#"
+//- /foo/Cargo.toml
+[package]
+name = "foo"
+version = "0.0.0"
+
+//- /foo/src/lib.rs
+pub fn foo() {}
+
+//- /bar/Cargo.toml
+[package]
+name = "bar"
+version = "0.0.0"
+
 //- /bar/src/lib.rs
 pub fn bar() {}
 
@@ -1388,7 +1492,7 @@ version = "0.0.0"
     .root("baz")
     .with_config(json!({
        "files": {
-           "excludeDirs": ["foo", "bar"]
+           "exclude": ["foo", "bar"]
         }
     }))
     .server()
diff --git a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs b/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs
index 4ec74c0742a..a35d50b78df 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs
@@ -1,28 +1,25 @@
 //! A micro-crate to enhance panic messages with context info.
-//!
-//! FIXME: upstream to <https://github.com/kriomant/panic-context> ?
 
 use std::{cell::RefCell, panic, sync::Once};
 
-pub fn enter(context: String) -> PanicContext {
-    static ONCE: Once = Once::new();
-    ONCE.call_once(PanicContext::init);
-
-    with_ctx(|ctx| ctx.push(context));
-    PanicContext { _priv: () }
-}
-
+/// Dummy for leveraging RAII cleanup to pop frames.
 #[must_use]
 pub struct PanicContext {
+    // prevent arbitrary construction
     _priv: (),
 }
 
-impl PanicContext {
+impl Drop for PanicContext {
+    fn drop(&mut self) {
+        with_ctx(|ctx| assert!(ctx.pop().is_some()));
+    }
+}
+
+pub fn enter(frame: String) -> PanicContext {
     #[allow(clippy::print_stderr)]
-    fn init() {
+    fn set_hook() {
         let default_hook = panic::take_hook();
-        #[allow(deprecated)]
-        let hook = move |panic_info: &panic::PanicInfo<'_>| {
+        panic::set_hook(Box::new(move |panic_info| {
             with_ctx(|ctx| {
                 if !ctx.is_empty() {
                     eprintln!("Panic context:");
@@ -30,17 +27,16 @@ impl PanicContext {
                         eprintln!("> {frame}\n");
                     }
                 }
-                default_hook(panic_info);
             });
-        };
-        panic::set_hook(Box::new(hook));
+            default_hook(panic_info);
+        }));
     }
-}
 
-impl Drop for PanicContext {
-    fn drop(&mut self) {
-        with_ctx(|ctx| assert!(ctx.pop().is_some()));
-    }
+    static SET_HOOK: Once = Once::new();
+    SET_HOOK.call_once(set_hook);
+
+    with_ctx(|ctx| ctx.push(frame));
+    PanicContext { _priv: () }
 }
 
 fn with_ctx(f: impl FnOnce(&mut Vec<String>)) {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
index 291fc646e21..aedf810b794 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
@@ -710,52 +710,6 @@ impl ast::Fn {
     }
 }
 
-impl Removable for ast::MatchArm {
-    fn remove(&self) {
-        if let Some(sibling) = self.syntax().prev_sibling_or_token() {
-            if sibling.kind() == SyntaxKind::WHITESPACE {
-                ted::remove(sibling);
-            }
-        }
-        if let Some(sibling) = self.syntax().next_sibling_or_token() {
-            if sibling.kind() == T![,] {
-                ted::remove(sibling);
-            }
-        }
-        ted::remove(self.syntax());
-    }
-}
-
-impl ast::MatchArmList {
-    pub fn add_arm(&self, arm: ast::MatchArm) {
-        normalize_ws_between_braces(self.syntax());
-        let mut elements = Vec::new();
-        let position = match self.arms().last() {
-            Some(last_arm) => {
-                if needs_comma(&last_arm) {
-                    ted::append_child(last_arm.syntax(), make::token(SyntaxKind::COMMA));
-                }
-                Position::after(last_arm.syntax().clone())
-            }
-            None => match self.l_curly_token() {
-                Some(it) => Position::after(it),
-                None => Position::last_child_of(self.syntax()),
-            },
-        };
-        let indent = IndentLevel::from_node(self.syntax()) + 1;
-        elements.push(make::tokens::whitespace(&format!("\n{indent}")).into());
-        elements.push(arm.syntax().clone().into());
-        if needs_comma(&arm) {
-            ted::append_child(arm.syntax(), make::token(SyntaxKind::COMMA));
-        }
-        ted::insert_all(position, elements);
-
-        fn needs_comma(arm: &ast::MatchArm) -> bool {
-            arm.expr().is_some_and(|e| !e.is_block_like()) && arm.comma_token().is_none()
-        }
-    }
-}
-
 impl ast::LetStmt {
     pub fn set_ty(&self, ty: Option<ast::Type>) {
         match ty {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index ff027ac5848..9dc2d832530 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -837,7 +837,8 @@ pub fn match_guard(condition: ast::Expr) -> ast::MatchGuard {
 
 pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
     let arms_str = arms.into_iter().fold(String::new(), |mut acc, arm| {
-        let needs_comma = arm.expr().is_none_or(|it| !it.is_block_like());
+        let needs_comma =
+            arm.comma_token().is_none() && arm.expr().is_none_or(|it| !it.is_block_like());
         let comma = if needs_comma { "," } else { "" };
         let arm = arm.syntax();
         format_to_acc!(acc, "    {arm}{comma}\n")
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 ca596583590..613f27c7958 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -17,7 +17,7 @@ use hir_expand::{
     tt::{Leaf, TokenTree, TopSubtree, TopSubtreeBuilder, TtElement, TtIter},
     FileRange,
 };
-use intern::Symbol;
+use intern::{sym, Symbol};
 use rustc_hash::FxHashMap;
 use span::{Edition, EditionedFileId, FileId, Span};
 use stdx::itertools::Itertools;
@@ -511,6 +511,21 @@ pub fn issue_18898(_attr: TokenStream, input: TokenStream) -> TokenStream {
                 disabled: false,
             },
         ),
+        (
+            r#"
+#[proc_macro_attribute]
+pub fn disallow_cfg(_attr: TokenStream, input: TokenStream) -> TokenStream {
+    input
+}
+"#
+            .into(),
+            ProcMacro {
+                name: Symbol::intern("disallow_cfg"),
+                kind: ProcMacroKind::Attr,
+                expander: sync::Arc::new(DisallowCfgProcMacroExpander),
+                disabled: false,
+            },
+        ),
     ])
 }
 
@@ -865,3 +880,30 @@ impl ProcMacroExpander for Issue18898ProcMacroExpander {
         })
     }
 }
+
+// Reads ident type within string quotes, for issue #17479.
+#[derive(Debug)]
+struct DisallowCfgProcMacroExpander;
+impl ProcMacroExpander for DisallowCfgProcMacroExpander {
+    fn expand(
+        &self,
+        subtree: &TopSubtree,
+        _: Option<&TopSubtree>,
+        _: &Env,
+        _: Span,
+        _: Span,
+        _: Span,
+        _: Option<String>,
+    ) -> Result<TopSubtree, ProcMacroExpansionError> {
+        for tt in subtree.token_trees().flat_tokens() {
+            if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = tt {
+                if ident.sym == sym::cfg || ident.sym == sym::cfg_attr {
+                    return Err(ProcMacroExpansionError::Panic(
+                        "cfg or cfg_attr found in DisallowCfgProcMacroExpander".to_owned(),
+                    ));
+                }
+            }
+        }
+        Ok(subtree.clone())
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs
index 36be9937d3f..e7279fa1f66 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs
@@ -396,12 +396,19 @@ pub fn skip_slow_tests() -> bool {
     if should_skip {
         eprintln!("ignoring slow test");
     } else {
-        let path = project_root().join("./target/.slow_tests_cookie");
+        let path = target_dir().join(".slow_tests_cookie");
         fs::write(path, ".").unwrap();
     }
     should_skip
 }
 
+pub fn target_dir() -> Utf8PathBuf {
+    match std::env::var("CARGO_TARGET_DIR") {
+        Ok(target) => Utf8PathBuf::from(target),
+        Err(_) => project_root().join("target"),
+    }
+}
+
 /// Returns the path to the root directory of `rust-analyzer` project.
 pub fn project_root() -> Utf8PathBuf {
     let dir = env!("CARGO_MANIFEST_DIR");
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index 4ed68d18e80..202afebde70 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -647,18 +647,21 @@ pub mod ops {
 
         #[lang = "fn"]
         #[fundamental]
+        #[rustc_paren_sugar]
         pub trait Fn<Args: Tuple>: FnMut<Args> {
             extern "rust-call" fn call(&self, args: Args) -> Self::Output;
         }
 
         #[lang = "fn_mut"]
         #[fundamental]
+        #[rustc_paren_sugar]
         pub trait FnMut<Args: Tuple>: FnOnce<Args> {
             extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
         }
 
         #[lang = "fn_once"]
         #[fundamental]
+        #[rustc_paren_sugar]
         pub trait FnOnce<Args: Tuple> {
             #[lang = "fn_once_output"]
             type Output;
@@ -736,12 +739,14 @@ pub mod ops {
 
         #[lang = "async_fn"]
         #[fundamental]
+        #[rustc_paren_sugar]
         pub trait AsyncFn<Args: Tuple>: AsyncFnMut<Args> {
             extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_>;
         }
 
         #[lang = "async_fn_mut"]
         #[fundamental]
+        #[rustc_paren_sugar]
         pub trait AsyncFnMut<Args: Tuple>: AsyncFnOnce<Args> {
             #[lang = "call_ref_future"]
             type CallRefFuture<'a>: Future<Output = Self::Output>
@@ -752,6 +757,7 @@ pub mod ops {
 
         #[lang = "async_fn_once"]
         #[fundamental]
+        #[rustc_paren_sugar]
         pub trait AsyncFnOnce<Args: Tuple> {
             #[lang = "async_fn_once_output"]
             type Output;
diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
index 0ae8b7baf46..32003341764 100644
--- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
@@ -280,8 +280,9 @@ impl NotifyActor {
                                 return false;
                             }
 
-                            root == path
-                                || dirs.exclude.iter().chain(&dirs.include).all(|it| it != path)
+                            // We want to filter out subdirectories that are roots themselves, because they will be visited separately.
+                            dirs.exclude.iter().all(|it| it != path)
+                                && (root == path || dirs.include.iter().all(|it| it != path))
                         });
 
                     let files = walkdir.filter_map(|it| it.ok()).filter_map(|entry| {
diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
index a26444e9ea2..3feca512e55 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
@@ -100,6 +100,9 @@ pub enum FileState {
     Exists(u64),
     /// The file is deleted.
     Deleted,
+    /// The file was specifically excluded by the user. We still include excluded files
+    /// when they're opened (without their contents).
+    Excluded,
 }
 
 /// Changed file in the [`Vfs`].
@@ -164,10 +167,22 @@ pub enum ChangeKind {
     Delete,
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum FileExcluded {
+    Yes,
+    No,
+}
+
 impl Vfs {
     /// Id of the given path if it exists in the `Vfs` and is not deleted.
-    pub fn file_id(&self, path: &VfsPath) -> Option<FileId> {
-        self.interner.get(path).filter(|&it| matches!(self.get(it), FileState::Exists(_)))
+    pub fn file_id(&self, path: &VfsPath) -> Option<(FileId, FileExcluded)> {
+        let file_id = self.interner.get(path)?;
+        let file_state = self.get(file_id);
+        match file_state {
+            FileState::Exists(_) => Some((file_id, FileExcluded::No)),
+            FileState::Deleted => None,
+            FileState::Excluded => Some((file_id, FileExcluded::Yes)),
+        }
     }
 
     /// File path corresponding to the given `file_id`.
@@ -216,6 +231,7 @@ impl Vfs {
                 }
                 Change::Modify(v, new_hash)
             }
+            (FileState::Excluded, _) => return false,
         };
 
         let mut set_data = |change_kind| {
@@ -297,6 +313,13 @@ impl Vfs {
     fn get(&self, file_id: FileId) -> FileState {
         self.data[file_id.0 as usize]
     }
+
+    /// We cannot ignore excluded files, because this will lead to errors when the client
+    /// requests semantic information for them, so we instead mark them specially.
+    pub fn insert_excluded_file(&mut self, path: VfsPath) {
+        let file_id = self.alloc_file_id(path);
+        self.data[file_id.0 as usize] = FileState::Excluded;
+    }
 }
 
 impl fmt::Debug for Vfs {
diff --git a/src/tools/rust-analyzer/docs/book/README.md b/src/tools/rust-analyzer/docs/book/README.md
index a9d10df6643..043524b2341 100644
--- a/src/tools/rust-analyzer/docs/book/README.md
+++ b/src/tools/rust-analyzer/docs/book/README.md
@@ -26,4 +26,4 @@ Start with the mdbook [User Guide](https://rust-lang.github.io/mdBook/guide/inst
 Four sections are generated dynamically: assists, configuration, diagnostics and features. Their content is found in the `generated.md` files
 of the respective book section, for example `src/configuration_generated.md`, and are included in the book via mdbook's
 [include](https://rust-lang.github.io/mdBook/format/mdbook.html#including-files) functionality. Generated files can be rebuilt by running the various
-test cases that generate them, or by simply running all of the `rust-analyzer` tests with `cargo test`.
+test cases that generate them, or by simply running all of the `rust-analyzer` tests with `cargo test` and `cargo xtask codegen`.
diff --git a/src/tools/rust-analyzer/docs/book/book.toml b/src/tools/rust-analyzer/docs/book/book.toml
index ba3c1dede5d..5ca4badde87 100644
--- a/src/tools/rust-analyzer/docs/book/book.toml
+++ b/src/tools/rust-analyzer/docs/book/book.toml
@@ -9,10 +9,10 @@ title = "rust-analyzer"
 edition = "2021"
 
 [output.html]
-edit-url-template = "https://github.com/rust-lang/rust-analyzer/edit/master/manual/{path}"
-git-repository-url = "https://github.com/rust-lang/rust-analyzer/tree/master/manual"
+edit-url-template = "https://github.com/rust-lang/rust-analyzer/edit/master/docs/book/{path}"
+git-repository-url = "https://github.com/rust-lang/rust-analyzer/tree/master/docs/book"
 mathjax-support = true
-site-url = "/manual/"
+site-url = "/book/"
 
 [output.html.playground]
 editable = true
@@ -34,8 +34,3 @@ use-boolean-and = true
 [output.html.fold]
 enable = true
 level = 3
-
-[preprocessor.toc]
-command = "mdbook-toc"
-renderer = ["html"]
-max-level = 3
diff --git a/src/tools/rust-analyzer/docs/book/src/SUMMARY.md b/src/tools/rust-analyzer/docs/book/src/SUMMARY.md
index b3ed1e6df0a..9dc4f1f2d2a 100644
--- a/src/tools/rust-analyzer/docs/book/src/SUMMARY.md
+++ b/src/tools/rust-analyzer/docs/book/src/SUMMARY.md
@@ -2,6 +2,9 @@
 
 - [Introduction](README.md)
 - [Installation](installation.md)
+  - [VS Code](vs_code.md)
+  - [rust-analyzer Binary](rust_analyzer_binary.md)
+  - [Other Editors](other_editors.md)
 - [Troubleshooting](troubleshooting.md)
 - [Configuration](configuration.md)
   - [Non-Cargo Based Projects](non_cargo_based_projects.md)
diff --git a/src/tools/rust-analyzer/docs/book/src/assists_generated.md b/src/tools/rust-analyzer/docs/book/src/assists_generated.md
new file mode 100644
index 00000000000..3617badeef5
--- /dev/null
+++ b/src/tools/rust-analyzer/docs/book/src/assists_generated.md
@@ -0,0 +1,3820 @@
+//! Generated by `cargo xtask codegen assists-doc-tests`, do not edit by hand.
+
+### `add_braces`
+**Source:**  [add_braces.rs](crates/ide-assists/src/handlers/add_braces.rs#8) 
+
+Adds braces to lambda and match arm expressions.
+
+#### Before
+```rust
+fn foo(n: i32) -> i32 {
+    match n {
+        1 =>┃ n + 1,
+        _ => 0
+    }
+}
+```
+
+#### After
+```rust
+fn foo(n: i32) -> i32 {
+    match n {
+        1 => {
+            n + 1
+        },
+        _ => 0
+    }
+}
+```
+
+
+### `add_explicit_type`
+**Source:**  [add_explicit_type.rs](crates/ide-assists/src/handlers/add_explicit_type.rs#7) 
+
+Specify type for a let binding.
+
+#### Before
+```rust
+fn main() {
+    let x┃ = 92;
+}
+```
+
+#### After
+```rust
+fn main() {
+    let x: i32 = 92;
+}
+```
+
+
+### `add_hash`
+**Source:**  [raw_string.rs](crates/ide-assists/src/handlers/raw_string.rs#89) 
+
+Adds a hash to a raw string literal.
+
+#### Before
+```rust
+fn main() {
+    r#"Hello,┃ World!"#;
+}
+```
+
+#### After
+```rust
+fn main() {
+    r##"Hello, World!"##;
+}
+```
+
+
+### `add_impl_default_members`
+**Source:**  [add_missing_impl_members.rs](crates/ide-assists/src/handlers/add_missing_impl_members.rs#58) 
+
+Adds scaffold for overriding default impl members.
+
+#### Before
+```rust
+trait Trait {
+    type X;
+    fn foo(&self);
+    fn bar(&self) {}
+}
+
+impl Trait for () {
+    type X = ();
+    fn foo(&self) {}┃
+}
+```
+
+#### After
+```rust
+trait Trait {
+    type X;
+    fn foo(&self);
+    fn bar(&self) {}
+}
+
+impl Trait for () {
+    type X = ();
+    fn foo(&self) {}
+
+    ┃fn bar(&self) {}
+}
+```
+
+
+### `add_impl_missing_members`
+**Source:**  [add_missing_impl_members.rs](crates/ide-assists/src/handlers/add_missing_impl_members.rs#16) 
+
+Adds scaffold for required impl members.
+
+#### Before
+```rust
+trait Trait<T> {
+    type X;
+    fn foo(&self) -> T;
+    fn bar(&self) {}
+}
+
+impl Trait<u32> for () {┃
+
+}
+```
+
+#### After
+```rust
+trait Trait<T> {
+    type X;
+    fn foo(&self) -> T;
+    fn bar(&self) {}
+}
+
+impl Trait<u32> for () {
+    ┃type X;
+
+    fn foo(&self) -> u32 {
+        todo!()
+    }
+}
+```
+
+
+### `add_label_to_loop`
+**Source:**  [add_label_to_loop.rs](crates/ide-assists/src/handlers/add_label_to_loop.rs#9) 
+
+Adds a label to a loop.
+
+#### Before
+```rust
+fn main() {
+    loop┃ {
+        break;
+        continue;
+    }
+}
+```
+
+#### After
+```rust
+fn main() {
+    'l: loop {
+        break 'l;
+        continue 'l;
+    }
+}
+```
+
+
+### `add_lifetime_to_type`
+**Source:**  [add_lifetime_to_type.rs](crates/ide-assists/src/handlers/add_lifetime_to_type.rs#5) 
+
+Adds a new lifetime to a struct, enum or union.
+
+#### Before
+```rust
+struct Point {
+    x: &┃u32,
+    y: u32,
+}
+```
+
+#### After
+```rust
+struct Point<'a> {
+    x: &'a u32,
+    y: u32,
+}
+```
+
+
+### `add_missing_match_arms`
+**Source:**  [add_missing_match_arms.rs](crates/ide-assists/src/handlers/add_missing_match_arms.rs#14) 
+
+Adds missing clauses to a `match` expression.
+
+#### Before
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        ┃
+    }
+}
+```
+
+#### After
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move { distance } => ${1:todo!()},
+        Action::Stop => ${2:todo!()},┃
+    }
+}
+```
+
+
+### `add_return_type`
+**Source:**  [add_return_type.rs](crates/ide-assists/src/handlers/add_return_type.rs#6) 
+
+Adds the return type to a function or closure inferred from its tail expression if it doesn't have a return
+type specified. This assists is useable in a functions or closures tail expression or return type position.
+
+#### Before
+```rust
+fn foo() { 4┃2i32 }
+```
+
+#### After
+```rust
+fn foo() -> i32 { 42i32 }
+```
+
+
+### `add_turbo_fish`
+**Source:**  [add_turbo_fish.rs](crates/ide-assists/src/handlers/add_turbo_fish.rs#14) 
+
+Adds `::<_>` to a call of a generic method or function.
+
+#### Before
+```rust
+fn make<T>() -> T { todo!() }
+fn main() {
+    let x = make┃();
+}
+```
+
+#### After
+```rust
+fn make<T>() -> T { todo!() }
+fn main() {
+    let x = make::<${0:_}>();
+}
+```
+
+
+### `apply_demorgan`
+**Source:**  [apply_demorgan.rs](crates/ide-assists/src/handlers/apply_demorgan.rs#16) 
+
+Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
+This transforms expressions of the form `!l || !r` into `!(l && r)`.
+This also works with `&&`. This assist can only be applied with the cursor
+on either `||` or `&&`.
+
+#### Before
+```rust
+fn main() {
+    if x != 4 ||┃ y < 3.14 {}
+}
+```
+
+#### After
+```rust
+fn main() {
+    if !(x == 4 && y >= 3.14) {}
+}
+```
+
+
+### `apply_demorgan_iterator`
+**Source:**  [apply_demorgan.rs](crates/ide-assists/src/handlers/apply_demorgan.rs#132) 
+
+Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws) to
+`Iterator::all` and `Iterator::any`.
+
+This transforms expressions of the form `!iter.any(|x| predicate(x))` into
+`iter.all(|x| !predicate(x))` and vice versa. This also works the other way for
+`Iterator::all` into `Iterator::any`.
+
+#### Before
+```rust
+fn main() {
+    let arr = [1, 2, 3];
+    if !arr.into_iter().┃any(|num| num == 4) {
+        println!("foo");
+    }
+}
+```
+
+#### After
+```rust
+fn main() {
+    let arr = [1, 2, 3];
+    if arr.into_iter().all(|num| num != 4) {
+        println!("foo");
+    }
+}
+```
+
+
+### `auto_import`
+**Source:**  [auto_import.rs](crates/ide-assists/src/handlers/auto_import.rs#73) 
+
+If the name is unresolved, provides all possible imports for it.
+
+#### Before
+```rust
+fn main() {
+    let map = HashMap┃::new();
+}
+```
+
+#### After
+```rust
+use std::collections::HashMap;
+
+fn main() {
+    let map = HashMap::new();
+}
+```
+
+
+### `bind_unused_param`
+**Source:**  [bind_unused_param.rs](crates/ide-assists/src/handlers/bind_unused_param.rs#12) 
+
+Binds unused function parameter to an underscore.
+
+#### Before
+```rust
+fn some_function(x: i32┃) {}
+```
+
+#### After
+```rust
+fn some_function(x: i32) {
+    let _ = x;
+}
+```
+
+
+### `bool_to_enum`
+**Source:**  [bool_to_enum.rs](crates/ide-assists/src/handlers/bool_to_enum.rs#29) 
+
+This converts boolean local variables, fields, constants, and statics into a new
+enum with two variants `Bool::True` and `Bool::False`, as well as replacing
+all assignments with the variants and replacing all usages with `== Bool::True` or
+`== Bool::False`.
+
+#### Before
+```rust
+fn main() {
+    let ┃bool = true;
+
+    if bool {
+        println!("foo");
+    }
+}
+```
+
+#### After
+```rust
+#[derive(PartialEq, Eq)]
+enum Bool { True, False }
+
+fn main() {
+    let bool = Bool::True;
+
+    if bool == Bool::True {
+        println!("foo");
+    }
+}
+```
+
+
+### `change_visibility`
+**Source:**  [change_visibility.rs](crates/ide-assists/src/handlers/change_visibility.rs#13) 
+
+Adds or changes existing visibility specifier.
+
+#### Before
+```rust
+┃fn frobnicate() {}
+```
+
+#### After
+```rust
+pub(crate) fn frobnicate() {}
+```
+
+
+### `comment_to_doc`
+**Source:**  [convert_comment_from_or_to_doc.rs](crates/ide-assists/src/handlers/convert_comment_from_or_to_doc.rs#9) 
+
+Converts comments to documentation.
+
+#### Before
+```rust
+// Wow what ┃a nice module
+// I sure hope this shows up when I hover over it
+```
+
+#### After
+```rust
+//! Wow what a nice module
+//! I sure hope this shows up when I hover over it
+```
+
+
+### `convert_bool_then_to_if`
+**Source:**  [convert_bool_then.rs](crates/ide-assists/src/handlers/convert_bool_then.rs#131) 
+
+Converts a `bool::then` method call to an equivalent if expression.
+
+#### Before
+```rust
+fn main() {
+    (0 == 0).then┃(|| val)
+}
+```
+
+#### After
+```rust
+fn main() {
+    if 0 == 0 {
+        Some(val)
+    } else {
+        None
+    }
+}
+```
+
+
+### `convert_closure_to_fn`
+**Source:**  [convert_closure_to_fn.rs](crates/ide-assists/src/handlers/convert_closure_to_fn.rs#25) 
+
+This converts a closure to a freestanding function, changing all captures to parameters.
+
+#### Before
+```rust
+fn main() {
+    let mut s = String::new();
+    let closure = |┃a| s.push_str(a);
+    closure("abc");
+}
+```
+
+#### After
+```rust
+fn main() {
+    let mut s = String::new();
+    fn closure(a: &str, s: &mut String) {
+        s.push_str(a)
+    }
+    closure("abc", &mut s);
+}
+```
+
+
+### `convert_for_loop_with_for_each`
+**Source:**  [convert_iter_for_each_to_for.rs](crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs#76) 
+
+Converts a for loop into a for_each loop on the Iterator.
+
+#### Before
+```rust
+fn main() {
+    let x = vec![1, 2, 3];
+    for┃ v in x {
+        let y = v * 2;
+    }
+}
+```
+
+#### After
+```rust
+fn main() {
+    let x = vec![1, 2, 3];
+    x.into_iter().for_each(|v| {
+        let y = v * 2;
+    });
+}
+```
+
+
+### `convert_from_to_tryfrom`
+**Source:**  [convert_from_to_tryfrom.rs](crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs#10) 
+
+Converts a From impl to a TryFrom impl, wrapping returns in `Ok`.
+
+#### Before
+```rust
+impl ┃From<usize> for Thing {
+    fn from(val: usize) -> Self {
+        Thing {
+            b: val.to_string(),
+            a: val
+        }
+    }
+}
+```
+
+#### After
+```rust
+impl TryFrom<usize> for Thing {
+    type Error = ${0:()};
+
+    fn try_from(val: usize) -> Result<Self, Self::Error> {
+        Ok(Thing {
+            b: val.to_string(),
+            a: val
+        })
+    }
+}
+```
+
+
+### `convert_if_to_bool_then`
+**Source:**  [convert_bool_then.rs](crates/ide-assists/src/handlers/convert_bool_then.rs#20) 
+
+Converts an if expression into a corresponding `bool::then` call.
+
+#### Before
+```rust
+fn main() {
+    if┃ cond {
+        Some(val)
+    } else {
+        None
+    }
+}
+```
+
+#### After
+```rust
+fn main() {
+    cond.then(|| val)
+}
+```
+
+
+### `convert_integer_literal`
+**Source:**  [convert_integer_literal.rs](crates/ide-assists/src/handlers/convert_integer_literal.rs#5) 
+
+Converts the base of integer literals to other bases.
+
+#### Before
+```rust
+const _: i32 = 10┃;
+```
+
+#### After
+```rust
+const _: i32 = 0b1010;
+```
+
+
+### `convert_into_to_from`
+**Source:**  [convert_into_to_from.rs](crates/ide-assists/src/handlers/convert_into_to_from.rs#8) 
+
+Converts an Into impl to an equivalent From impl.
+
+#### Before
+```rust
+impl ┃Into<Thing> for usize {
+    fn into(self) -> Thing {
+        Thing {
+            b: self.to_string(),
+            a: self
+        }
+    }
+}
+```
+
+#### After
+```rust
+impl From<usize> for Thing {
+    fn from(val: usize) -> Self {
+        Thing {
+            b: val.to_string(),
+            a: val
+        }
+    }
+}
+```
+
+
+### `convert_iter_for_each_to_for`
+**Source:**  [convert_iter_for_each_to_for.rs](crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs#11) 
+
+Converts an Iterator::for_each function into a for loop.
+
+#### Before
+```rust
+fn main() {
+    let iter = iter::repeat((9, 2));
+    iter.for_each┃(|(x, y)| {
+        println!("x: {}, y: {}", x, y);
+    });
+}
+```
+
+#### After
+```rust
+fn main() {
+    let iter = iter::repeat((9, 2));
+    for (x, y) in iter {
+        println!("x: {}, y: {}", x, y);
+    }
+}
+```
+
+
+### `convert_let_else_to_match`
+**Source:**  [convert_let_else_to_match.rs](crates/ide-assists/src/handlers/convert_let_else_to_match.rs#9) 
+
+Converts let-else statement to let statement and match expression.
+
+#### Before
+```rust
+fn main() {
+    let Ok(mut x) = f() else┃ { return };
+}
+```
+
+#### After
+```rust
+fn main() {
+    let mut x = match f() {
+        Ok(x) => x,
+        _ => return,
+    };
+}
+```
+
+
+### `convert_match_to_let_else`
+**Source:**  [convert_match_to_let_else.rs](crates/ide-assists/src/handlers/convert_match_to_let_else.rs#12) 
+
+Converts let statement with match initializer to let-else statement.
+
+#### Before
+```rust
+fn foo(opt: Option<()>) {
+    let val┃ = match opt {
+        Some(it) => it,
+        None => return,
+    };
+}
+```
+
+#### After
+```rust
+fn foo(opt: Option<()>) {
+    let Some(val) = opt else { return };
+}
+```
+
+
+### `convert_named_struct_to_tuple_struct`
+**Source:**  [convert_named_struct_to_tuple_struct.rs](crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs#11) 
+
+Converts struct with named fields to tuple struct, and analogously for enum variants with named
+fields.
+
+#### Before
+```rust
+struct Point┃ { x: f32, y: f32 }
+
+impl Point {
+    pub fn new(x: f32, y: f32) -> Self {
+        Point { x, y }
+    }
+
+    pub fn x(&self) -> f32 {
+        self.x
+    }
+
+    pub fn y(&self) -> f32 {
+        self.y
+    }
+}
+```
+
+#### After
+```rust
+struct Point(f32, f32);
+
+impl Point {
+    pub fn new(x: f32, y: f32) -> Self {
+        Point(x, y)
+    }
+
+    pub fn x(&self) -> f32 {
+        self.0
+    }
+
+    pub fn y(&self) -> f32 {
+        self.1
+    }
+}
+```
+
+
+### `convert_nested_function_to_closure`
+**Source:**  [convert_nested_function_to_closure.rs](crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs#7) 
+
+Converts a function that is defined within the body of another function into a closure.
+
+#### Before
+```rust
+fn main() {
+    fn fo┃o(label: &str, number: u64) {
+        println!("{}: {}", label, number);
+    }
+
+    foo("Bar", 100);
+}
+```
+
+#### After
+```rust
+fn main() {
+    let foo = |label: &str, number: u64| {
+        println!("{}: {}", label, number);
+    };
+
+    foo("Bar", 100);
+}
+```
+
+
+### `convert_to_guarded_return`
+**Source:**  [convert_to_guarded_return.rs](crates/ide-assists/src/handlers/convert_to_guarded_return.rs#24) 
+
+Replace a large conditional with a guarded return.
+
+#### Before
+```rust
+fn main() {
+    ┃if cond {
+        foo();
+        bar();
+    }
+}
+```
+
+#### After
+```rust
+fn main() {
+    if !cond {
+        return;
+    }
+    foo();
+    bar();
+}
+```
+
+
+### `convert_tuple_return_type_to_struct`
+**Source:**  [convert_tuple_return_type_to_struct.rs](crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs#20) 
+
+This converts the return type of a function from a tuple type
+into a tuple struct and updates the body accordingly.
+
+#### Before
+```rust
+fn bar() {
+    let (a, b, c) = foo();
+}
+
+fn foo() -> (┃u32, u32, u32) {
+    (1, 2, 3)
+}
+```
+
+#### After
+```rust
+fn bar() {
+    let FooResult(a, b, c) = foo();
+}
+
+struct FooResult(u32, u32, u32);
+
+fn foo() -> FooResult {
+    FooResult(1, 2, 3)
+}
+```
+
+
+### `convert_tuple_struct_to_named_struct`
+**Source:**  [convert_tuple_struct_to_named_struct.rs](crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs#10) 
+
+Converts tuple struct to struct with named fields, and analogously for tuple enum variants.
+
+#### Before
+```rust
+struct Point┃(f32, f32);
+
+impl Point {
+    pub fn new(x: f32, y: f32) -> Self {
+        Point(x, y)
+    }
+
+    pub fn x(&self) -> f32 {
+        self.0
+    }
+
+    pub fn y(&self) -> f32 {
+        self.1
+    }
+}
+```
+
+#### After
+```rust
+struct Point { field1: f32, field2: f32 }
+
+impl Point {
+    pub fn new(x: f32, y: f32) -> Self {
+        Point { field1: x, field2: y }
+    }
+
+    pub fn x(&self) -> f32 {
+        self.field1
+    }
+
+    pub fn y(&self) -> f32 {
+        self.field2
+    }
+}
+```
+
+
+### `convert_two_arm_bool_match_to_matches_macro`
+**Source:**  [convert_two_arm_bool_match_to_matches_macro.rs](crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs#8) 
+
+Convert 2-arm match that evaluates to a boolean into the equivalent matches! invocation.
+
+#### Before
+```rust
+fn main() {
+    match scrutinee┃ {
+        Some(val) if val.cond() => true,
+        _ => false,
+    }
+}
+```
+
+#### After
+```rust
+fn main() {
+    matches!(scrutinee, Some(val) if val.cond())
+}
+```
+
+
+### `convert_while_to_loop`
+**Source:**  [convert_while_to_loop.rs](crates/ide-assists/src/handlers/convert_while_to_loop.rs#20) 
+
+Replace a while with a loop.
+
+#### Before
+```rust
+fn main() {
+    ┃while cond {
+        foo();
+    }
+}
+```
+
+#### After
+```rust
+fn main() {
+    loop {
+        if !cond {
+            break;
+        }
+        foo();
+    }
+}
+```
+
+
+### `destructure_struct_binding`
+**Source:**  [destructure_struct_binding.rs](crates/ide-assists/src/handlers/destructure_struct_binding.rs#18) 
+
+Destructures a struct binding in place.
+
+#### Before
+```rust
+struct Foo {
+    bar: i32,
+    baz: i32,
+}
+fn main() {
+    let ┃foo = Foo { bar: 1, baz: 2 };
+    let bar2 = foo.bar;
+    let baz2 = &foo.baz;
+}
+```
+
+#### After
+```rust
+struct Foo {
+    bar: i32,
+    baz: i32,
+}
+fn main() {
+    let Foo { bar, baz } = Foo { bar: 1, baz: 2 };
+    let bar2 = bar;
+    let baz2 = &baz;
+}
+```
+
+
+### `destructure_tuple_binding`
+**Source:**  [destructure_tuple_binding.rs](crates/ide-assists/src/handlers/destructure_tuple_binding.rs#19) 
+
+Destructures a tuple binding in place.
+
+#### Before
+```rust
+fn main() {
+    let ┃t = (1,2);
+    let v = t.0;
+}
+```
+
+#### After
+```rust
+fn main() {
+    let (┃_0, _1) = (1,2);
+    let v = _0;
+}
+```
+
+
+### `desugar_async_into_impl_future`
+**Source:**  [toggle_async_sugar.rs](crates/ide-assists/src/handlers/toggle_async_sugar.rs#103) 
+
+Rewrites asynchronous function from `async fn` into `-> impl Future`.
+This action does not touch the function body and therefore `0`
+block does not transform to `async { 0 }`.
+
+#### Before
+```rust
+pub as┃ync fn foo() -> usize {
+    0
+}
+```
+
+#### After
+```rust
+pub fn foo() -> impl core::future::Future<Output = usize> {
+    0
+}
+```
+
+
+### `desugar_doc_comment`
+**Source:**  [desugar_doc_comment.rs](crates/ide-assists/src/handlers/desugar_doc_comment.rs#14) 
+
+Desugars doc-comments to the attribute form.
+
+#### Before
+```rust
+/// Multi-line┃
+/// comment
+```
+
+#### After
+```rust
+#[doc = r"Multi-line
+comment"]
+```
+
+
+### `expand_glob_import`
+**Source:**  [expand_glob_import.rs](crates/ide-assists/src/handlers/expand_glob_import.rs#18) 
+
+Expands glob imports.
+
+#### Before
+```rust
+mod foo {
+    pub struct Bar;
+    pub struct Baz;
+}
+
+use foo::*┃;
+
+fn qux(bar: Bar, baz: Baz) {}
+```
+
+#### After
+```rust
+mod foo {
+    pub struct Bar;
+    pub struct Baz;
+}
+
+use foo::{Bar, Baz};
+
+fn qux(bar: Bar, baz: Baz) {}
+```
+
+
+### `explicit_enum_discriminant`
+**Source:**  [explicit_enum_discriminant.rs](crates/ide-assists/src/handlers/explicit_enum_discriminant.rs#11) 
+
+Adds explicit discriminant to all enum variants.
+
+#### Before
+```rust
+enum TheEnum┃ {
+    Foo,
+    Bar,
+    Baz = 42,
+    Quux,
+}
+```
+
+#### After
+```rust
+enum TheEnum {
+    Foo = 0,
+    Bar = 1,
+    Baz = 42,
+    Quux = 43,
+}
+```
+
+
+### `extract_constant`
+**Source:**  [extract_variable.rs](crates/ide-assists/src/handlers/extract_variable.rs#35) 
+
+Extracts subexpression into a constant.
+
+#### Before
+```rust
+fn main() {
+    ┃(1 + 2)┃ * 4;
+}
+```
+
+#### After
+```rust
+fn main() {
+    const ┃VAR_NAME: i32 = 1 + 2;
+    VAR_NAME * 4;
+}
+```
+
+
+### `extract_expressions_from_format_string`
+**Source:**  [extract_expressions_from_format_string.rs](crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs#14) 
+
+Move an expression out of a format string.
+
+#### Before
+```rust
+fn main() {
+    print!("{var} {x + 1}┃");
+}
+```
+
+#### After
+```rust
+fn main() {
+    print!("{var} {}"┃, x + 1);
+}
+```
+
+
+### `extract_function`
+**Source:**  [extract_function.rs](crates/ide-assists/src/handlers/extract_function.rs#39) 
+
+Extracts selected statements and comments into new function.
+
+#### Before
+```rust
+fn main() {
+    let n = 1;
+    ┃let m = n + 2;
+    // calculate
+    let k = m + n;┃
+    let g = 3;
+}
+```
+
+#### After
+```rust
+fn main() {
+    let n = 1;
+    fun_name(n);
+    let g = 3;
+}
+
+fn ┃fun_name(n: i32) {
+    let m = n + 2;
+    // calculate
+    let k = m + n;
+}
+```
+
+
+### `extract_module`
+**Source:**  [extract_module.rs](crates/ide-assists/src/handlers/extract_module.rs#29) 
+
+Extracts a selected region as separate module. All the references, visibility and imports are
+resolved.
+
+#### Before
+```rust
+┃fn foo(name: i32) -> i32 {
+    name + 1
+}┃
+
+fn bar(name: i32) -> i32 {
+    name + 2
+}
+```
+
+#### After
+```rust
+mod modname {
+    pub(crate) fn foo(name: i32) -> i32 {
+        name + 1
+    }
+}
+
+fn bar(name: i32) -> i32 {
+    name + 2
+}
+```
+
+
+### `extract_static`
+**Source:**  [extract_variable.rs](crates/ide-assists/src/handlers/extract_variable.rs#52) 
+
+Extracts subexpression into a static.
+
+#### Before
+```rust
+fn main() {
+    ┃(1 + 2)┃ * 4;
+}
+```
+
+#### After
+```rust
+fn main() {
+    static ┃VAR_NAME: i32 = 1 + 2;
+    VAR_NAME * 4;
+}
+```
+
+
+### `extract_struct_from_enum_variant`
+**Source:**  [extract_struct_from_enum_variant.rs](crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs#26) 
+
+Extracts a struct from enum variant.
+
+#### Before
+```rust
+enum A { ┃One(u32, u32) }
+```
+
+#### After
+```rust
+struct One(u32, u32);
+
+enum A { One(One) }
+```
+
+
+### `extract_type_alias`
+**Source:**  [extract_type_alias.rs](crates/ide-assists/src/handlers/extract_type_alias.rs#10) 
+
+Extracts the selected type as a type alias.
+
+#### Before
+```rust
+struct S {
+    field: ┃(u8, u8, u8)┃,
+}
+```
+
+#### After
+```rust
+type ┃Type = (u8, u8, u8);
+
+struct S {
+    field: Type,
+}
+```
+
+
+### `extract_variable`
+**Source:**  [extract_variable.rs](crates/ide-assists/src/handlers/extract_variable.rs#18) 
+
+Extracts subexpression into a variable.
+
+#### Before
+```rust
+fn main() {
+    ┃(1 + 2)┃ * 4;
+}
+```
+
+#### After
+```rust
+fn main() {
+    let ┃var_name = 1 + 2;
+    var_name * 4;
+}
+```
+
+
+### `fill_record_pattern_fields`
+**Source:**  [fill_record_pattern_fields.rs](crates/ide-assists/src/handlers/fill_record_pattern_fields.rs#8) 
+
+Fills fields by replacing rest pattern in record patterns.
+
+#### Before
+```rust
+struct Bar { y: Y, z: Z }
+
+fn foo(bar: Bar) {
+    let Bar { ..┃ } = bar;
+}
+```
+
+#### After
+```rust
+struct Bar { y: Y, z: Z }
+
+fn foo(bar: Bar) {
+    let Bar { y, z  } = bar;
+}
+```
+
+
+### `fix_visibility`
+**Source:**  [fix_visibility.rs](crates/ide-assists/src/handlers/fix_visibility.rs#14) 
+
+Makes inaccessible item public.
+
+#### Before
+```rust
+mod m {
+    fn frobnicate() {}
+}
+fn main() {
+    m::frobnicate┃();
+}
+```
+
+#### After
+```rust
+mod m {
+    ┃pub(crate) fn frobnicate() {}
+}
+fn main() {
+    m::frobnicate();
+}
+```
+
+
+### `flip_binexpr`
+**Source:**  [flip_binexpr.rs](crates/ide-assists/src/handlers/flip_binexpr.rs#8) 
+
+Flips operands of a binary expression.
+
+#### Before
+```rust
+fn main() {
+    let _ = 90 +┃ 2;
+}
+```
+
+#### After
+```rust
+fn main() {
+    let _ = 2 + 90;
+}
+```
+
+
+### `flip_comma`
+**Source:**  [flip_comma.rs](crates/ide-assists/src/handlers/flip_comma.rs#10) 
+
+Flips two comma-separated items.
+
+#### Before
+```rust
+fn main() {
+    ((1, 2),┃ (3, 4));
+}
+```
+
+#### After
+```rust
+fn main() {
+    ((3, 4), (1, 2));
+}
+```
+
+
+### `flip_trait_bound`
+**Source:**  [flip_trait_bound.rs](crates/ide-assists/src/handlers/flip_trait_bound.rs#9) 
+
+Flips two trait bounds.
+
+#### Before
+```rust
+fn foo<T: Clone +┃ Copy>() { }
+```
+
+#### After
+```rust
+fn foo<T: Copy + Clone>() { }
+```
+
+
+### `generate_constant`
+**Source:**  [generate_constant.rs](crates/ide-assists/src/handlers/generate_constant.rs#14) 
+
+Generate a named constant.
+
+#### Before
+```rust
+struct S { i: usize }
+impl S { pub fn new(n: usize) {} }
+fn main() {
+    let v = S::new(CAPA┃CITY);
+}
+```
+
+#### After
+```rust
+struct S { i: usize }
+impl S { pub fn new(n: usize) {} }
+fn main() {
+    const CAPACITY: usize = ┃;
+    let v = S::new(CAPACITY);
+}
+```
+
+
+### `generate_default_from_enum_variant`
+**Source:**  [generate_default_from_enum_variant.rs](crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs#6) 
+
+Adds a Default impl for an enum using a variant.
+
+#### Before
+```rust
+enum Version {
+ Undefined,
+ Minor┃,
+ Major,
+}
+```
+
+#### After
+```rust
+enum Version {
+ Undefined,
+ Minor,
+ Major,
+}
+
+impl Default for Version {
+    fn default() -> Self {
+        Self::Minor
+    }
+}
+```
+
+
+### `generate_default_from_new`
+**Source:**  [generate_default_from_new.rs](crates/ide-assists/src/handlers/generate_default_from_new.rs#13) 
+
+Generates default implementation from new method.
+
+#### Before
+```rust
+struct Example { _inner: () }
+
+impl Example {
+    pub fn n┃ew() -> Self {
+        Self { _inner: () }
+    }
+}
+```
+
+#### After
+```rust
+struct Example { _inner: () }
+
+impl Example {
+    pub fn new() -> Self {
+        Self { _inner: () }
+    }
+}
+
+impl Default for Example {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+```
+
+
+### `generate_delegate_methods`
+**Source:**  [generate_delegate_methods.rs](crates/ide-assists/src/handlers/generate_delegate_methods.rs#15) 
+
+Generate delegate methods.
+
+#### Before
+```rust
+struct Age(u8);
+impl Age {
+    fn age(&self) -> u8 {
+        self.0
+    }
+}
+
+struct Person {
+    ag┃e: Age,
+}
+```
+
+#### After
+```rust
+struct Age(u8);
+impl Age {
+    fn age(&self) -> u8 {
+        self.0
+    }
+}
+
+struct Person {
+    age: Age,
+}
+
+impl Person {
+    ┃fn age(&self) -> u8 {
+        self.age.age()
+    }
+}
+```
+
+
+### `generate_delegate_trait`
+**Source:**  [generate_delegate_trait.rs](crates/ide-assists/src/handlers/generate_delegate_trait.rs#29) 
+
+Generate delegate trait implementation for `StructField`s.
+
+#### Before
+```rust
+trait SomeTrait {
+    type T;
+    fn fn_(arg: u32) -> u32;
+    fn method_(&mut self) -> bool;
+}
+struct A;
+impl SomeTrait for A {
+    type T = u32;
+
+    fn fn_(arg: u32) -> u32 {
+        42
+    }
+
+    fn method_(&mut self) -> bool {
+        false
+    }
+}
+struct B {
+    a┃: A,
+}
+```
+
+#### After
+```rust
+trait SomeTrait {
+    type T;
+    fn fn_(arg: u32) -> u32;
+    fn method_(&mut self) -> bool;
+}
+struct A;
+impl SomeTrait for A {
+    type T = u32;
+
+    fn fn_(arg: u32) -> u32 {
+        42
+    }
+
+    fn method_(&mut self) -> bool {
+        false
+    }
+}
+struct B {
+    a: A,
+}
+
+impl SomeTrait for B {
+    type T = <A as SomeTrait>::T;
+
+    fn fn_(arg: u32) -> u32 {
+        <A as SomeTrait>::fn_(arg)
+    }
+
+    fn method_(&mut self) -> bool {
+        <A as SomeTrait>::method_(&mut self.a)
+    }
+}
+```
+
+
+### `generate_deref`
+**Source:**  [generate_deref.rs](crates/ide-assists/src/handlers/generate_deref.rs#16) 
+
+Generate `Deref` impl using the given struct field.
+
+#### Before
+```rust
+struct A;
+struct B {
+   ┃a: A
+}
+```
+
+#### After
+```rust
+struct A;
+struct B {
+   a: A
+}
+
+impl core::ops::Deref for B {
+    type Target = A;
+
+    fn deref(&self) -> &Self::Target {
+        &self.a
+    }
+}
+```
+
+
+### `generate_derive`
+**Source:**  [generate_derive.rs](crates/ide-assists/src/handlers/generate_derive.rs#8) 
+
+Adds a new `#[derive()]` clause to a struct or enum.
+
+#### Before
+```rust
+struct Point {
+    x: u32,
+    y: u32,┃
+}
+```
+
+#### After
+```rust
+#[derive(┃)]
+struct Point {
+    x: u32,
+    y: u32,
+}
+```
+
+
+### `generate_doc_example`
+**Source:**  [generate_documentation_template.rs](crates/ide-assists/src/handlers/generate_documentation_template.rs#76) 
+
+Generates a rustdoc example when editing an item's documentation.
+
+#### Before
+```rust
+/// Adds two numbers.┃
+pub fn add(a: i32, b: i32) -> i32 { a + b }
+```
+
+#### After
+```rust
+/// Adds two numbers.
+///
+/// # Examples
+///
+/// ```
+/// use ra_test_fixture::add;
+///
+/// assert_eq!(add(a, b), );
+/// ```
+pub fn add(a: i32, b: i32) -> i32 { a + b }
+```
+
+
+### `generate_documentation_template`
+**Source:**  [generate_documentation_template.rs](crates/ide-assists/src/handlers/generate_documentation_template.rs#13) 
+
+Adds a documentation template above a function definition / declaration.
+
+#### Before
+```rust
+pub struct S;
+impl S {
+    pub unsafe fn set_len┃(&mut self, len: usize) -> Result<(), std::io::Error> {
+        /* ... */
+    }
+}
+```
+
+#### After
+```rust
+pub struct S;
+impl S {
+    /// Sets the length of this [`S`].
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if .
+    ///
+    /// # Safety
+    ///
+    /// .
+    pub unsafe fn set_len(&mut self, len: usize) -> Result<(), std::io::Error> {
+        /* ... */
+    }
+}
+```
+
+
+### `generate_enum_as_method`
+**Source:**  [generate_enum_projection_method.rs](crates/ide-assists/src/handlers/generate_enum_projection_method.rs#59) 
+
+Generate an `as_` method for this enum variant.
+
+#### Before
+```rust
+enum Value {
+ Number(i32),
+ Text(String)┃,
+}
+```
+
+#### After
+```rust
+enum Value {
+ Number(i32),
+ Text(String),
+}
+
+impl Value {
+    fn as_text(&self) -> Option<&String> {
+        if let Self::Text(v) = self {
+            Some(v)
+        } else {
+            None
+        }
+    }
+}
+```
+
+
+### `generate_enum_is_method`
+**Source:**  [generate_enum_is_method.rs](crates/ide-assists/src/handlers/generate_enum_is_method.rs#11) 
+
+Generate an `is_` method for this enum variant.
+
+#### Before
+```rust
+enum Version {
+ Undefined,
+ Minor┃,
+ Major,
+}
+```
+
+#### After
+```rust
+enum Version {
+ Undefined,
+ Minor,
+ Major,
+}
+
+impl Version {
+    /// Returns `true` if the version is [`Minor`].
+    ///
+    /// [`Minor`]: Version::Minor
+    #[must_use]
+    fn is_minor(&self) -> bool {
+        matches!(self, Self::Minor)
+    }
+}
+```
+
+
+### `generate_enum_try_into_method`
+**Source:**  [generate_enum_projection_method.rs](crates/ide-assists/src/handlers/generate_enum_projection_method.rs#12) 
+
+Generate a `try_into_` method for this enum variant.
+
+#### Before
+```rust
+enum Value {
+ Number(i32),
+ Text(String)┃,
+}
+```
+
+#### After
+```rust
+enum Value {
+ Number(i32),
+ Text(String),
+}
+
+impl Value {
+    fn try_into_text(self) -> Result<String, Self> {
+        if let Self::Text(v) = self {
+            Ok(v)
+        } else {
+            Err(self)
+        }
+    }
+}
+```
+
+
+### `generate_enum_variant`
+**Source:**  [generate_enum_variant.rs](crates/ide-assists/src/handlers/generate_enum_variant.rs#10) 
+
+Adds a variant to an enum.
+
+#### Before
+```rust
+enum Countries {
+    Ghana,
+}
+
+fn main() {
+    let country = Countries::Lesotho┃;
+}
+```
+
+#### After
+```rust
+enum Countries {
+    Ghana,
+    Lesotho,
+}
+
+fn main() {
+    let country = Countries::Lesotho;
+}
+```
+
+
+### `generate_fn_type_alias_named`
+**Source:**  [generate_fn_type_alias.rs](crates/ide-assists/src/handlers/generate_fn_type_alias.rs#10) 
+
+Generate a type alias for the function with named parameters.
+
+#### Before
+```rust
+unsafe fn fo┃o(n: i32) -> i32 { 42i32 }
+```
+
+#### After
+```rust
+type ${0:FooFn} = unsafe fn(n: i32) -> i32;
+
+unsafe fn foo(n: i32) -> i32 { 42i32 }
+```
+
+
+### `generate_fn_type_alias_unnamed`
+**Source:**  [generate_fn_type_alias.rs](crates/ide-assists/src/handlers/generate_fn_type_alias.rs#24) 
+
+Generate a type alias for the function with unnamed parameters.
+
+#### Before
+```rust
+unsafe fn fo┃o(n: i32) -> i32 { 42i32 }
+```
+
+#### After
+```rust
+type ${0:FooFn} = unsafe fn(i32) -> i32;
+
+unsafe fn foo(n: i32) -> i32 { 42i32 }
+```
+
+
+### `generate_from_impl_for_enum`
+**Source:**  [generate_from_impl_for_enum.rs](crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs#8) 
+
+Adds a From impl for this enum variant with one tuple field.
+
+#### Before
+```rust
+enum A { ┃One(u32) }
+```
+
+#### After
+```rust
+enum A { One(u32) }
+
+impl From<u32> for A {
+    fn from(v: u32) -> Self {
+        Self::One(v)
+    }
+}
+```
+
+
+### `generate_function`
+**Source:**  [generate_function.rs](crates/ide-assists/src/handlers/generate_function.rs#28) 
+
+Adds a stub function with a signature matching the function under the cursor.
+
+#### Before
+```rust
+struct Baz;
+fn baz() -> Baz { Baz }
+fn foo() {
+    bar┃("", baz());
+}
+
+```
+
+#### After
+```rust
+struct Baz;
+fn baz() -> Baz { Baz }
+fn foo() {
+    bar("", baz());
+}
+
+fn bar(arg: &str, baz: Baz) ${0:-> _} {
+    todo!()
+}
+
+```
+
+
+### `generate_getter`
+**Source:**  [generate_getter_or_setter.rs](crates/ide-assists/src/handlers/generate_getter_or_setter.rs#73) 
+
+Generate a getter method.
+
+#### Before
+```rust
+struct Person {
+    nam┃e: String,
+}
+```
+
+#### After
+```rust
+struct Person {
+    name: String,
+}
+
+impl Person {
+    fn ┃name(&self) -> &str {
+        &self.name
+    }
+}
+```
+
+
+### `generate_getter_mut`
+**Source:**  [generate_getter_or_setter.rs](crates/ide-assists/src/handlers/generate_getter_or_setter.rs#127) 
+
+Generate a mut getter method.
+
+#### Before
+```rust
+struct Person {
+    nam┃e: String,
+}
+```
+
+#### After
+```rust
+struct Person {
+    name: String,
+}
+
+impl Person {
+    fn ┃name_mut(&mut self) -> &mut String {
+        &mut self.name
+    }
+}
+```
+
+
+### `generate_impl`
+**Source:**  [generate_impl.rs](crates/ide-assists/src/handlers/generate_impl.rs#20) 
+
+Adds a new inherent impl for a type.
+
+#### Before
+```rust
+struct Ctx┃<T: Clone> {
+    data: T,
+}
+```
+
+#### After
+```rust
+struct Ctx<T: Clone> {
+    data: T,
+}
+
+impl<T: Clone> Ctx<T> {┃}
+```
+
+
+### `generate_is_empty_from_len`
+**Source:**  [generate_is_empty_from_len.rs](crates/ide-assists/src/handlers/generate_is_empty_from_len.rs#12) 
+
+Generates is_empty implementation from the len method.
+
+#### Before
+```rust
+struct MyStruct { data: Vec<String> }
+
+impl MyStruct {
+    #[must_use]
+    p┃ub fn len(&self) -> usize {
+        self.data.len()
+    }
+}
+```
+
+#### After
+```rust
+struct MyStruct { data: Vec<String> }
+
+impl MyStruct {
+    #[must_use]
+    pub fn len(&self) -> usize {
+        self.data.len()
+    }
+
+    #[must_use]
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+}
+```
+
+
+### `generate_mut_trait_impl`
+**Source:**  [generate_mut_trait_impl.rs](crates/ide-assists/src/handlers/generate_mut_trait_impl.rs#12) 
+
+Adds a IndexMut impl from the `Index` trait.
+
+#### Before
+```rust
+pub enum Axis { X = 0, Y = 1, Z = 2 }
+
+impl<T> core::ops::Index┃<Axis> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: Axis) -> &Self::Output {
+        &self[index as usize]
+    }
+}
+```
+
+#### After
+```rust
+pub enum Axis { X = 0, Y = 1, Z = 2 }
+
+┃impl<T> core::ops::IndexMut<Axis> for [T; 3] {
+    fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
+        &self[index as usize]
+    }
+}
+
+impl<T> core::ops::Index<Axis> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: Axis) -> &Self::Output {
+        &self[index as usize]
+    }
+}
+```
+
+
+### `generate_new`
+**Source:**  [generate_new.rs](crates/ide-assists/src/handlers/generate_new.rs#14) 
+
+Adds a `fn new` for a type.
+
+#### Before
+```rust
+struct Ctx<T: Clone> {
+     data: T,┃
+}
+```
+
+#### After
+```rust
+struct Ctx<T: Clone> {
+     data: T,
+}
+
+impl<T: Clone> Ctx<T> {
+    fn ┃new(data: T) -> Self {
+        Self { data }
+    }
+}
+```
+
+
+### `generate_setter`
+**Source:**  [generate_getter_or_setter.rs](crates/ide-assists/src/handlers/generate_getter_or_setter.rs#13) 
+
+Generate a setter method.
+
+#### Before
+```rust
+struct Person {
+    nam┃e: String,
+}
+```
+
+#### After
+```rust
+struct Person {
+    name: String,
+}
+
+impl Person {
+    fn ┃set_name(&mut self, name: String) {
+        self.name = name;
+    }
+}
+```
+
+
+### `generate_trait_from_impl`
+**Source:**  [generate_trait_from_impl.rs](crates/ide-assists/src/handlers/generate_trait_from_impl.rs#18) 
+
+Generate trait for an already defined inherent impl and convert impl to a trait impl.
+
+#### Before
+```rust
+struct Foo<const N: usize>([i32; N]);
+
+macro_rules! const_maker {
+    ($t:ty, $v:tt) => {
+        const CONST: $t = $v;
+    };
+}
+
+impl<const N: usize> Fo┃o<N> {
+    // Used as an associated constant.
+    const CONST_ASSOC: usize = N * 4;
+
+    fn create() -> Option<()> {
+        Some(())
+    }
+
+    const_maker! {i32, 7}
+}
+```
+
+#### After
+```rust
+struct Foo<const N: usize>([i32; N]);
+
+macro_rules! const_maker {
+    ($t:ty, $v:tt) => {
+        const CONST: $t = $v;
+    };
+}
+
+trait ${0:NewTrait}<const N: usize> {
+    // Used as an associated constant.
+    const CONST_ASSOC: usize = N * 4;
+
+    fn create() -> Option<()>;
+
+    const_maker! {i32, 7}
+}
+
+impl<const N: usize> ${0:NewTrait}<N> for Foo<N> {
+    // Used as an associated constant.
+    const CONST_ASSOC: usize = N * 4;
+
+    fn create() -> Option<()> {
+        Some(())
+    }
+
+    const_maker! {i32, 7}
+}
+```
+
+
+### `generate_trait_impl`
+**Source:**  [generate_impl.rs](crates/ide-assists/src/handlers/generate_impl.rs#66) 
+
+Adds a new trait impl for a type.
+
+#### Before
+```rust
+struct ┃Ctx<T: Clone> {
+    data: T,
+}
+```
+
+#### After
+```rust
+struct Ctx<T: Clone> {
+    data: T,
+}
+
+impl<T: Clone> ${0:_} for Ctx<T> {}
+```
+
+
+### `inline_call`
+**Source:**  [inline_call.rs](crates/ide-assists/src/handlers/inline_call.rs#170) 
+
+Inlines a function or method body creating a `let` statement per parameter unless the parameter
+can be inlined. The parameter will be inlined either if it the supplied argument is a simple local
+or if the parameter is only accessed inside the function body once.
+
+#### Before
+```rust
+fn foo(name: Option<&str>) {
+    let name = name.unwrap┃();
+}
+```
+
+#### After
+```rust
+fn foo(name: Option<&str>) {
+    let name = match name {
+            Some(val) => val,
+            None => panic!("called `Option::unwrap()` on a `None` value"),
+        };
+}
+```
+
+
+### `inline_const_as_literal`
+**Source:**  [inline_const_as_literal.rs](crates/ide-assists/src/handlers/inline_const_as_literal.rs#6) 
+
+Evaluate and inline const variable as literal.
+
+#### Before
+```rust
+const STRING: &str = "Hello, World!";
+
+fn something() -> &'static str {
+    STRING┃
+}
+```
+
+#### After
+```rust
+const STRING: &str = "Hello, World!";
+
+fn something() -> &'static str {
+    "Hello, World!"
+}
+```
+
+
+### `inline_into_callers`
+**Source:**  [inline_call.rs](crates/ide-assists/src/handlers/inline_call.rs#32) 
+
+Inline a function or method body into all of its callers where possible, creating a `let` statement per parameter
+unless the parameter can be inlined. The parameter will be inlined either if it the supplied argument is a simple local
+or if the parameter is only accessed inside the function body once.
+If all calls can be inlined the function will be removed.
+
+#### Before
+```rust
+fn print(_: &str) {}
+fn foo┃(word: &str) {
+    if !word.is_empty() {
+        print(word);
+    }
+}
+fn bar() {
+    foo("안녕하세요");
+    foo("여러분");
+}
+```
+
+#### After
+```rust
+fn print(_: &str) {}
+
+fn bar() {
+    {
+        let word: &str = "안녕하세요";
+        if !word.is_empty() {
+            print(word);
+        }
+    };
+    {
+        let word: &str = "여러분";
+        if !word.is_empty() {
+            print(word);
+        }
+    };
+}
+```
+
+
+### `inline_local_variable`
+**Source:**  [inline_local_variable.rs](crates/ide-assists/src/handlers/inline_local_variable.rs#17) 
+
+Inlines a local variable.
+
+#### Before
+```rust
+fn main() {
+    let x┃ = 1 + 2;
+    x * 4;
+}
+```
+
+#### After
+```rust
+fn main() {
+    (1 + 2) * 4;
+}
+```
+
+
+### `inline_macro`
+**Source:**  [inline_macro.rs](crates/ide-assists/src/handlers/inline_macro.rs#7) 
+
+Takes a macro and inlines it one step.
+
+#### Before
+```rust
+macro_rules! num {
+    (+$($t:tt)+) => (1 + num!($($t )+));
+    (-$($t:tt)+) => (-1 + num!($($t )+));
+    (+) => (1);
+    (-) => (-1);
+}
+
+fn main() {
+    let number = num┃!(+ + + - + +);
+    println!("{number}");
+}
+```
+
+#### After
+```rust
+macro_rules! num {
+    (+$($t:tt)+) => (1 + num!($($t )+));
+    (-$($t:tt)+) => (-1 + num!($($t )+));
+    (+) => (1);
+    (-) => (-1);
+}
+
+fn main() {
+    let number = 1+num!(+ + - + +);
+    println!("{number}");
+}
+```
+
+
+### `inline_type_alias`
+**Source:**  [inline_type_alias.rs](crates/ide-assists/src/handlers/inline_type_alias.rs#106) 
+
+Replace a type alias with its concrete type.
+
+#### Before
+```rust
+type A<T = u32> = Vec<T>;
+
+fn main() {
+    let a: ┃A;
+}
+```
+
+#### After
+```rust
+type A<T = u32> = Vec<T>;
+
+fn main() {
+    let a: Vec<u32>;
+}
+```
+
+
+### `inline_type_alias_uses`
+**Source:**  [inline_type_alias.rs](crates/ide-assists/src/handlers/inline_type_alias.rs#24) 
+
+Inline a type alias into all of its uses where possible.
+
+#### Before
+```rust
+type ┃A = i32;
+fn id(x: A) -> A {
+    x
+};
+fn foo() {
+    let _: A = 3;
+}
+```
+
+#### After
+```rust
+
+fn id(x: i32) -> i32 {
+    x
+};
+fn foo() {
+    let _: i32 = 3;
+}
+```
+
+
+### `into_to_qualified_from`
+**Source:**  [into_to_qualified_from.rs](crates/ide-assists/src/handlers/into_to_qualified_from.rs#10) 
+
+Convert an `into` method call to a fully qualified `from` call.
+
+#### Before
+```rust
+//- minicore: from
+struct B;
+impl From<i32> for B {
+    fn from(a: i32) -> Self {
+       B
+    }
+}
+
+fn main() -> () {
+    let a = 3;
+    let b: B = a.in┃to();
+}
+```
+
+#### After
+```rust
+struct B;
+impl From<i32> for B {
+    fn from(a: i32) -> Self {
+       B
+    }
+}
+
+fn main() -> () {
+    let a = 3;
+    let b: B = B::from(a);
+}
+```
+
+
+### `introduce_named_generic`
+**Source:**  [introduce_named_generic.rs](crates/ide-assists/src/handlers/introduce_named_generic.rs#7) 
+
+Replaces `impl Trait` function argument with the named generic.
+
+#### Before
+```rust
+fn foo(bar: ┃impl Bar) {}
+```
+
+#### After
+```rust
+fn foo<┃B: Bar>(bar: B) {}
+```
+
+
+### `introduce_named_lifetime`
+**Source:**  [introduce_named_lifetime.rs](crates/ide-assists/src/handlers/introduce_named_lifetime.rs#13) 
+
+Change an anonymous lifetime to a named lifetime.
+
+#### Before
+```rust
+impl Cursor<'_┃> {
+    fn node(self) -> &SyntaxNode {
+        match self {
+            Cursor::Replace(node) | Cursor::Before(node) => node,
+        }
+    }
+}
+```
+
+#### After
+```rust
+impl<'a> Cursor<'a> {
+    fn node(self) -> &SyntaxNode {
+        match self {
+            Cursor::Replace(node) | Cursor::Before(node) => node,
+        }
+    }
+}
+```
+
+
+### `invert_if`
+**Source:**  [invert_if.rs](crates/ide-assists/src/handlers/invert_if.rs#13) 
+
+This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}`
+This also works with `!=`. This assist can only be applied with the cursor on `if`.
+
+#### Before
+```rust
+fn main() {
+    if┃ !y { A } else { B }
+}
+```
+
+#### After
+```rust
+fn main() {
+    if y { B } else { A }
+}
+```
+
+
+### `line_to_block`
+**Source:**  [convert_comment_block.rs](crates/ide-assists/src/handlers/convert_comment_block.rs#9) 
+
+Converts comments between block and single-line form.
+
+#### Before
+```rust
+   // Multi-line┃
+   // comment
+```
+
+#### After
+```rust
+  /*
+  Multi-line
+  comment
+  */
+```
+
+
+### `make_raw_string`
+**Source:**  [raw_string.rs](crates/ide-assists/src/handlers/raw_string.rs#7) 
+
+Adds `r#` to a plain string literal.
+
+#### Before
+```rust
+fn main() {
+    "Hello,┃ World!";
+}
+```
+
+#### After
+```rust
+fn main() {
+    r#"Hello, World!"#;
+}
+```
+
+
+### `make_usual_string`
+**Source:**  [raw_string.rs](crates/ide-assists/src/handlers/raw_string.rs#47) 
+
+Turns a raw string into a plain string.
+
+#### Before
+```rust
+fn main() {
+    r#"Hello,┃ "World!""#;
+}
+```
+
+#### After
+```rust
+fn main() {
+    "Hello, \"World!\"";
+}
+```
+
+
+### `merge_imports`
+**Source:**  [merge_imports.rs](crates/ide-assists/src/handlers/merge_imports.rs#21) 
+
+Merges neighbor imports with a common prefix.
+
+#### Before
+```rust
+use std::┃fmt::Formatter;
+use std::io;
+```
+
+#### After
+```rust
+use std::{fmt::Formatter, io};
+```
+
+
+### `merge_match_arms`
+**Source:**  [merge_match_arms.rs](crates/ide-assists/src/handlers/merge_match_arms.rs#12) 
+
+Merges the current match arm with the following if their bodies are identical.
+
+#### Before
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        ┃Action::Move(..) => foo(),
+        Action::Stop => foo(),
+    }
+}
+```
+
+#### After
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move(..) | Action::Stop => foo(),
+    }
+}
+```
+
+
+### `merge_nested_if`
+**Source:**  [merge_nested_if.rs](crates/ide-assists/src/handlers/merge_nested_if.rs#11) 
+
+This transforms if expressions of the form `if x { if y {A} }` into `if x && y {A}`
+This assist can only be applied with the cursor on `if`.
+
+#### Before
+```rust
+fn main() {
+   i┃f x == 3 { if y == 4 { 1 } }
+}
+```
+
+#### After
+```rust
+fn main() {
+   if x == 3 && y == 4 { 1 }
+}
+```
+
+
+### `move_arm_cond_to_match_guard`
+**Source:**  [move_guard.rs](crates/ide-assists/src/handlers/move_guard.rs#69) 
+
+Moves if expression from match arm body into a guard.
+
+#### Before
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move { distance } => ┃if distance > 10 { foo() },
+        _ => (),
+    }
+}
+```
+
+#### After
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move { distance } if distance > 10 => foo(),
+        _ => (),
+    }
+}
+```
+
+
+### `move_bounds_to_where_clause`
+**Source:**  [move_bounds.rs](crates/ide-assists/src/handlers/move_bounds.rs#12) 
+
+Moves inline type bounds to a where clause.
+
+#### Before
+```rust
+fn apply<T, U, ┃F: FnOnce(T) -> U>(f: F, x: T) -> U {
+    f(x)
+}
+```
+
+#### After
+```rust
+fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
+    f(x)
+}
+```
+
+
+### `move_const_to_impl`
+**Source:**  [move_const_to_impl.rs](crates/ide-assists/src/handlers/move_const_to_impl.rs#14) 
+
+Move a local constant item in a method to impl's associated constant. All the references will be
+qualified with `Self::`.
+
+#### Before
+```rust
+struct S;
+impl S {
+    fn foo() -> usize {
+        /// The answer.
+        const C┃: usize = 42;
+
+        C * C
+    }
+}
+```
+
+#### After
+```rust
+struct S;
+impl S {
+    /// The answer.
+    const C: usize = 42;
+
+    fn foo() -> usize {
+        Self::C * Self::C
+    }
+}
+```
+
+
+### `move_from_mod_rs`
+**Source:**  [move_from_mod_rs.rs](crates/ide-assists/src/handlers/move_from_mod_rs.rs#12) 
+
+Moves xxx/mod.rs to xxx.rs.
+
+#### Before
+```rust
+//- /main.rs
+mod a;
+//- /a/mod.rs
+┃fn t() {}┃
+```
+
+#### After
+```rust
+fn t() {}
+```
+
+
+### `move_guard_to_arm_body`
+**Source:**  [move_guard.rs](crates/ide-assists/src/handlers/move_guard.rs#8) 
+
+Moves match guard into match arm body.
+
+#### Before
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move { distance } ┃if distance > 10 => foo(),
+        _ => (),
+    }
+}
+```
+
+#### After
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move { distance } => if distance > 10 {
+            foo()
+        },
+        _ => (),
+    }
+}
+```
+
+
+### `move_module_to_file`
+**Source:**  [move_module_to_file.rs](crates/ide-assists/src/handlers/move_module_to_file.rs#15) 
+
+Moves inline module's contents to a separate file.
+
+#### Before
+```rust
+mod ┃foo {
+    fn t() {}
+}
+```
+
+#### After
+```rust
+mod foo;
+```
+
+
+### `move_to_mod_rs`
+**Source:**  [move_to_mod_rs.rs](crates/ide-assists/src/handlers/move_to_mod_rs.rs#12) 
+
+Moves xxx.rs to xxx/mod.rs.
+
+#### Before
+```rust
+//- /main.rs
+mod a;
+//- /a.rs
+┃fn t() {}┃
+```
+
+#### After
+```rust
+fn t() {}
+```
+
+
+### `normalize_import`
+**Source:**  [normalize_import.rs](crates/ide-assists/src/handlers/normalize_import.rs#9) 
+
+Normalizes an import.
+
+#### Before
+```rust
+use┃ std::{io, {fmt::Formatter}};
+```
+
+#### After
+```rust
+use std::{fmt::Formatter, io};
+```
+
+
+### `promote_local_to_const`
+**Source:**  [promote_local_to_const.rs](crates/ide-assists/src/handlers/promote_local_to_const.rs#17) 
+
+Promotes a local variable to a const item changing its name to a `SCREAMING_SNAKE_CASE` variant
+if the local uses no non-const expressions.
+
+#### Before
+```rust
+fn main() {
+    let foo┃ = true;
+
+    if foo {
+        println!("It's true");
+    } else {
+        println!("It's false");
+    }
+}
+```
+
+#### After
+```rust
+fn main() {
+    const ┃FOO: bool = true;
+
+    if FOO {
+        println!("It's true");
+    } else {
+        println!("It's false");
+    }
+}
+```
+
+
+### `pull_assignment_up`
+**Source:**  [pull_assignment_up.rs](crates/ide-assists/src/handlers/pull_assignment_up.rs#11) 
+
+Extracts variable assignment to outside an if or match statement.
+
+#### Before
+```rust
+fn main() {
+    let mut foo = 6;
+
+    if true {
+        ┃foo = 5;
+    } else {
+        foo = 4;
+    }
+}
+```
+
+#### After
+```rust
+fn main() {
+    let mut foo = 6;
+
+    foo = if true {
+        5
+    } else {
+        4
+    };
+}
+```
+
+
+### `qualify_method_call`
+**Source:**  [qualify_method_call.rs](crates/ide-assists/src/handlers/qualify_method_call.rs#10) 
+
+Replaces the method call with a qualified function call.
+
+#### Before
+```rust
+struct Foo;
+impl Foo {
+    fn foo(&self) {}
+}
+fn main() {
+    let foo = Foo;
+    foo.fo┃o();
+}
+```
+
+#### After
+```rust
+struct Foo;
+impl Foo {
+    fn foo(&self) {}
+}
+fn main() {
+    let foo = Foo;
+    Foo::foo(&foo);
+}
+```
+
+
+### `qualify_path`
+**Source:**  [qualify_path.rs](crates/ide-assists/src/handlers/qualify_path.rs#24) 
+
+If the name is unresolved, provides all possible qualified paths for it.
+
+#### Before
+```rust
+fn main() {
+    let map = HashMap┃::new();
+}
+```
+
+#### After
+```rust
+fn main() {
+    let map = std::collections::HashMap::new();
+}
+```
+
+
+### `reformat_number_literal`
+**Source:**  [number_representation.rs](crates/ide-assists/src/handlers/number_representation.rs#7) 
+
+Adds or removes separators from integer literal.
+
+#### Before
+```rust
+const _: i32 = 1012345┃;
+```
+
+#### After
+```rust
+const _: i32 = 1_012_345;
+```
+
+
+### `remove_dbg`
+**Source:**  [remove_dbg.rs](crates/ide-assists/src/handlers/remove_dbg.rs#9) 
+
+Removes `dbg!()` macro call.
+
+#### Before
+```rust
+fn main() {
+    let x = ┃dbg!(42 * dbg!(4 + 2));┃
+}
+```
+
+#### After
+```rust
+fn main() {
+    let x = 42 * (4 + 2);
+}
+```
+
+
+### `remove_hash`
+**Source:**  [raw_string.rs](crates/ide-assists/src/handlers/raw_string.rs#117) 
+
+Removes a hash from a raw string literal.
+
+#### Before
+```rust
+fn main() {
+    r#"Hello,┃ World!"#;
+}
+```
+
+#### After
+```rust
+fn main() {
+    r"Hello, World!";
+}
+```
+
+
+### `remove_mut`
+**Source:**  [remove_mut.rs](crates/ide-assists/src/handlers/remove_mut.rs#5) 
+
+Removes the `mut` keyword.
+
+#### Before
+```rust
+impl Walrus {
+    fn feed(&mut┃ self, amount: u32) {}
+}
+```
+
+#### After
+```rust
+impl Walrus {
+    fn feed(&self, amount: u32) {}
+}
+```
+
+
+### `remove_parentheses`
+**Source:**  [remove_parentheses.rs](crates/ide-assists/src/handlers/remove_parentheses.rs#5) 
+
+Removes redundant parentheses.
+
+#### Before
+```rust
+fn main() {
+    _ = ┃(2) + 2;
+}
+```
+
+#### After
+```rust
+fn main() {
+    _ = 2 + 2;
+}
+```
+
+
+### `remove_unused_imports`
+**Source:**  [remove_unused_imports.rs](crates/ide-assists/src/handlers/remove_unused_imports.rs#17) 
+
+Removes any use statements in the current selection that are unused.
+
+#### Before
+```rust
+struct X();
+mod foo {
+    use super::X┃;
+}
+```
+
+#### After
+```rust
+struct X();
+mod foo {
+}
+```
+
+
+### `remove_unused_param`
+**Source:**  [remove_unused_param.rs](crates/ide-assists/src/handlers/remove_unused_param.rs#15) 
+
+Removes unused function parameter.
+
+#### Before
+```rust
+fn frobnicate(x: i32┃) {}
+
+fn main() {
+    frobnicate(92);
+}
+```
+
+#### After
+```rust
+fn frobnicate() {}
+
+fn main() {
+    frobnicate();
+}
+```
+
+
+### `reorder_fields`
+**Source:**  [reorder_fields.rs](crates/ide-assists/src/handlers/reorder_fields.rs#8) 
+
+Reorder the fields of record literals and record patterns in the same order as in
+the definition.
+
+#### Before
+```rust
+struct Foo {foo: i32, bar: i32};
+const test: Foo = ┃Foo {bar: 0, foo: 1}
+```
+
+#### After
+```rust
+struct Foo {foo: i32, bar: i32};
+const test: Foo = Foo {foo: 1, bar: 0}
+```
+
+
+### `reorder_impl_items`
+**Source:**  [reorder_impl_items.rs](crates/ide-assists/src/handlers/reorder_impl_items.rs#11) 
+
+Reorder the items of an `impl Trait`. The items will be ordered
+in the same order as in the trait definition.
+
+#### Before
+```rust
+trait Foo {
+    type A;
+    const B: u8;
+    fn c();
+}
+
+struct Bar;
+┃impl Foo for Bar┃ {
+    const B: u8 = 17;
+    fn c() {}
+    type A = String;
+}
+```
+
+#### After
+```rust
+trait Foo {
+    type A;
+    const B: u8;
+    fn c();
+}
+
+struct Bar;
+impl Foo for Bar {
+    type A = String;
+    const B: u8 = 17;
+    fn c() {}
+}
+```
+
+
+### `replace_arith_with_checked`
+**Source:**  [replace_arith_op.rs](crates/ide-assists/src/handlers/replace_arith_op.rs#9) 
+
+Replaces arithmetic on integers with the `checked_*` equivalent.
+
+#### Before
+```rust
+fn main() {
+  let x = 1 ┃+ 2;
+}
+```
+
+#### After
+```rust
+fn main() {
+  let x = 1.checked_add(2);
+}
+```
+
+
+### `replace_arith_with_saturating`
+**Source:**  [replace_arith_op.rs](crates/ide-assists/src/handlers/replace_arith_op.rs#28) 
+
+Replaces arithmetic on integers with the `saturating_*` equivalent.
+
+#### Before
+```rust
+fn main() {
+  let x = 1 ┃+ 2;
+}
+```
+
+#### After
+```rust
+fn main() {
+  let x = 1.saturating_add(2);
+}
+```
+
+
+### `replace_arith_with_wrapping`
+**Source:**  [replace_arith_op.rs](crates/ide-assists/src/handlers/replace_arith_op.rs#50) 
+
+Replaces arithmetic on integers with the `wrapping_*` equivalent.
+
+#### Before
+```rust
+fn main() {
+  let x = 1 ┃+ 2;
+}
+```
+
+#### After
+```rust
+fn main() {
+  let x = 1.wrapping_add(2);
+}
+```
+
+
+### `replace_char_with_string`
+**Source:**  [replace_string_with_char.rs](crates/ide-assists/src/handlers/replace_string_with_char.rs#51) 
+
+Replace a char literal with a string literal.
+
+#### Before
+```rust
+fn main() {
+    find('{┃');
+}
+```
+
+#### After
+```rust
+fn main() {
+    find("{");
+}
+```
+
+
+### `replace_derive_with_manual_impl`
+**Source:**  [replace_derive_with_manual_impl.rs](crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs#20) 
+
+Converts a `derive` impl into a manual one.
+
+#### Before
+```rust
+#[derive(Deb┃ug, Display)]
+struct S;
+```
+
+#### After
+```rust
+#[derive(Display)]
+struct S;
+
+impl Debug for S {
+    ┃fn fmt(&self, f: &mut Formatter) -> Result<()> {
+        f.debug_struct("S").finish()
+    }
+}
+```
+
+
+### `replace_if_let_with_match`
+**Source:**  [replace_if_let_with_match.rs](crates/ide-assists/src/handlers/replace_if_let_with_match.rs#20) 
+
+Replaces a `if let` expression with a `match` expression.
+
+#### Before
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    ┃if let Action::Move { distance } = action {
+        foo(distance)
+    } else {
+        bar()
+    }
+}
+```
+
+#### After
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move { distance } => foo(distance),
+        _ => bar(),
+    }
+}
+```
+
+
+### `replace_is_some_with_if_let_some`
+**Source:**  [replace_is_method_with_if_let_method.rs](crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs#9) 
+
+Replace `if x.is_some()` with `if let Some(_tmp) = x` or `if x.is_ok()` with `if let Ok(_tmp) = x`.
+
+#### Before
+```rust
+fn main() {
+    let x = Some(1);
+    if x.is_som┃e() {}
+}
+```
+
+#### After
+```rust
+fn main() {
+    let x = Some(1);
+    if let Some(${0:x1}) = x {}
+}
+```
+
+
+### `replace_let_with_if_let`
+**Source:**  [replace_let_with_if_let.rs](crates/ide-assists/src/handlers/replace_let_with_if_let.rs#9) 
+
+Replaces `let` with an `if let`.
+
+#### Before
+```rust
+
+fn main(action: Action) {
+    ┃let x = compute();
+}
+
+fn compute() -> Option<i32> { None }
+```
+
+#### After
+```rust
+
+fn main(action: Action) {
+    if let Some(x) = compute() {
+    }
+}
+
+fn compute() -> Option<i32> { None }
+```
+
+
+### `replace_match_with_if_let`
+**Source:**  [replace_if_let_with_match.rs](crates/ide-assists/src/handlers/replace_if_let_with_match.rs#188) 
+
+Replaces a binary `match` with a wildcard pattern and no guards with an `if let` expression.
+
+#### Before
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    ┃match action {
+        Action::Move { distance } => foo(distance),
+        _ => bar(),
+    }
+}
+```
+
+#### After
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    if let Action::Move { distance } = action {
+        foo(distance)
+    } else {
+        bar()
+    }
+}
+```
+
+
+### `replace_named_generic_with_impl`
+**Source:**  [replace_named_generic_with_impl.rs](crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs#18) 
+
+Replaces named generic with an `impl Trait` in function argument.
+
+#### Before
+```rust
+fn new<P┃: AsRef<Path>>(location: P) -> Self {}
+```
+
+#### After
+```rust
+fn new(location: impl AsRef<Path>) -> Self {}
+```
+
+
+### `replace_qualified_name_with_use`
+**Source:**  [replace_qualified_name_with_use.rs](crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs#13) 
+
+Adds a use statement for a given fully-qualified name.
+
+#### Before
+```rust
+fn process(map: std::collections::┃HashMap<String, String>) {}
+```
+
+#### After
+```rust
+use std::collections::HashMap;
+
+fn process(map: HashMap<String, String>) {}
+```
+
+
+### `replace_string_with_char`
+**Source:**  [replace_string_with_char.rs](crates/ide-assists/src/handlers/replace_string_with_char.rs#11) 
+
+Replace string literal with char literal.
+
+#### Before
+```rust
+fn main() {
+    find("{┃");
+}
+```
+
+#### After
+```rust
+fn main() {
+    find('{');
+}
+```
+
+
+### `replace_try_expr_with_match`
+**Source:**  [replace_try_expr_with_match.rs](crates/ide-assists/src/handlers/replace_try_expr_with_match.rs#18) 
+
+Replaces a `try` expression with a `match` expression.
+
+#### Before
+```rust
+fn handle() {
+    let pat = Some(true)┃?;
+}
+```
+
+#### After
+```rust
+fn handle() {
+    let pat = match Some(true) {
+        Some(it) => it,
+        None => return None,
+    };
+}
+```
+
+
+### `replace_turbofish_with_explicit_type`
+**Source:**  [replace_turbofish_with_explicit_type.rs](crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs#12) 
+
+Converts `::<_>` to an explicit type assignment.
+
+#### Before
+```rust
+fn make<T>() -> T { ) }
+fn main() {
+    let a = make┃::<i32>();
+}
+```
+
+#### After
+```rust
+fn make<T>() -> T { ) }
+fn main() {
+    let a: i32 = make();
+}
+```
+
+
+### `replace_with_eager_method`
+**Source:**  [replace_method_eager_lazy.rs](crates/ide-assists/src/handlers/replace_method_eager_lazy.rs#89) 
+
+Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
+
+#### Before
+```rust
+fn foo() {
+    let a = Some(1);
+    a.unwra┃p_or_else(|| 2);
+}
+```
+
+#### After
+```rust
+fn foo() {
+    let a = Some(1);
+    a.unwrap_or(2);
+}
+```
+
+
+### `replace_with_lazy_method`
+**Source:**  [replace_method_eager_lazy.rs](crates/ide-assists/src/handlers/replace_method_eager_lazy.rs#9) 
+
+Replace `unwrap_or` with `unwrap_or_else` and `ok_or` with `ok_or_else`.
+
+#### Before
+```rust
+fn foo() {
+    let a = Some(1);
+    a.unwra┃p_or(2);
+}
+```
+
+#### After
+```rust
+fn foo() {
+    let a = Some(1);
+    a.unwrap_or_else(|| 2);
+}
+```
+
+
+### `sort_items`
+**Source:**  [sort_items.rs](crates/ide-assists/src/handlers/sort_items.rs#12) 
+
+Sorts item members alphabetically: fields, enum variants and methods.
+
+#### Before
+```rust
+struct ┃Foo┃ { second: u32, first: String }
+```
+
+#### After
+```rust
+struct Foo { first: String, second: u32 }
+```
+
+---
+
+#### Before
+```rust
+trait ┃Bar┃ {
+    fn second(&self) -> u32;
+    fn first(&self) -> String;
+}
+```
+
+#### After
+```rust
+trait Bar {
+    fn first(&self) -> String;
+    fn second(&self) -> u32;
+}
+```
+
+---
+
+#### Before
+```rust
+struct Baz;
+impl ┃Baz┃ {
+    fn second(&self) -> u32;
+    fn first(&self) -> String;
+}
+```
+
+#### After
+```rust
+struct Baz;
+impl Baz {
+    fn first(&self) -> String;
+    fn second(&self) -> u32;
+}
+```
+
+---
+There is a difference between sorting enum variants:
+
+#### Before
+```rust
+enum ┃Animal┃ {
+  Dog(String, f64),
+  Cat { weight: f64, name: String },
+}
+```
+
+#### After
+```rust
+enum Animal {
+  Cat { weight: f64, name: String },
+  Dog(String, f64),
+}
+```
+
+and sorting a single enum struct variant:
+
+#### Before
+```rust
+enum Animal {
+  Dog(String, f64),
+  Cat ┃{ weight: f64, name: String }┃,
+}
+```
+
+#### After
+```rust
+enum Animal {
+  Dog(String, f64),
+  Cat { name: String, weight: f64 },
+}
+```
+
+
+### `split_import`
+**Source:**  [split_import.rs](crates/ide-assists/src/handlers/split_import.rs#5) 
+
+Wraps the tail of import into braces.
+
+#### Before
+```rust
+use std::┃collections::HashMap;
+```
+
+#### After
+```rust
+use std::{collections::HashMap};
+```
+
+
+### `sugar_impl_future_into_async`
+**Source:**  [toggle_async_sugar.rs](crates/ide-assists/src/handlers/toggle_async_sugar.rs#13) 
+
+Rewrites asynchronous function from `-> impl Future` into `async fn`.
+This action does not touch the function body and therefore `async { 0 }`
+block does not transform to just `0`.
+
+#### Before
+```rust
+pub fn foo() -> impl core::future::F┃uture<Output = usize> {
+    async { 0 }
+}
+```
+
+#### After
+```rust
+pub async fn foo() -> usize {
+    async { 0 }
+}
+```
+
+
+### `toggle_ignore`
+**Source:**  [toggle_ignore.rs](crates/ide-assists/src/handlers/toggle_ignore.rs#8) 
+
+Adds `#[ignore]` attribute to the test.
+
+#### Before
+```rust
+┃#[test]
+fn arithmetics {
+    assert_eq!(2 + 2, 5);
+}
+```
+
+#### After
+```rust
+#[test]
+#[ignore]
+fn arithmetics {
+    assert_eq!(2 + 2, 5);
+}
+```
+
+
+### `toggle_macro_delimiter`
+**Source:**  [toggle_macro_delimiter.rs](crates/ide-assists/src/handlers/toggle_macro_delimiter.rs#9) 
+
+Change macro delimiters in the order of `( -> { -> [ -> (`.
+
+#### Before
+```rust
+macro_rules! sth {
+    () => {};
+}
+
+sth!┃( );
+```
+
+#### After
+```rust
+macro_rules! sth {
+    () => {};
+}
+
+sth!{ }
+```
+
+
+### `unmerge_match_arm`
+**Source:**  [unmerge_match_arm.rs](crates/ide-assists/src/handlers/unmerge_match_arm.rs#10) 
+
+Splits the current match with a `|` pattern into two arms with identical bodies.
+
+#### Before
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move(..) ┃| Action::Stop => foo(),
+    }
+}
+```
+
+#### After
+```rust
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move(..) => foo(),
+        Action::Stop => foo(),
+    }
+}
+```
+
+
+### `unmerge_use`
+**Source:**  [unmerge_use.rs](crates/ide-assists/src/handlers/unmerge_use.rs#12) 
+
+Extracts single use item from use list.
+
+#### Before
+```rust
+use std::fmt::{Debug, Display┃};
+```
+
+#### After
+```rust
+use std::fmt::{Debug};
+use std::fmt::Display;
+```
+
+
+### `unnecessary_async`
+**Source:**  [unnecessary_async.rs](crates/ide-assists/src/handlers/unnecessary_async.rs#17) 
+
+Removes the `async` mark from functions which have no `.await` in their body.
+Looks for calls to the functions and removes the `.await` on the call site.
+
+#### Before
+```rust
+pub asy┃nc fn foo() {}
+pub async fn bar() { foo().await }
+```
+
+#### After
+```rust
+pub fn foo() {}
+pub async fn bar() { foo() }
+```
+
+
+### `unqualify_method_call`
+**Source:**  [unqualify_method_call.rs](crates/ide-assists/src/handlers/unqualify_method_call.rs#9) 
+
+Transforms universal function call syntax into a method call.
+
+#### Before
+```rust
+fn main() {
+    std::ops::Add::add┃(1, 2);
+}
+```
+
+#### After
+```rust
+use std::ops::Add;
+
+fn main() {
+    1.add(2);
+}
+```
+
+
+### `unwrap_block`
+**Source:**  [unwrap_block.rs](crates/ide-assists/src/handlers/unwrap_block.rs#12) 
+
+This assist removes if...else, for, while and loop control statements to just keep the body.
+
+#### Before
+```rust
+fn foo() {
+    if true {┃
+        println!("foo");
+    }
+}
+```
+
+#### After
+```rust
+fn foo() {
+    println!("foo");
+}
+```
+
+
+### `unwrap_option_return_type`
+**Source:**  [unwrap_return_type.rs](crates/ide-assists/src/handlers/unwrap_return_type.rs#13) 
+
+Unwrap the function's return type.
+
+#### Before
+```rust
+fn foo() -> Option<i32>┃ { Some(42i32) }
+```
+
+#### After
+```rust
+fn foo() -> i32 { 42i32 }
+```
+
+
+### `unwrap_result_return_type`
+**Source:**  [unwrap_return_type.rs](crates/ide-assists/src/handlers/unwrap_return_type.rs#26) 
+
+Unwrap the function's return type.
+
+#### Before
+```rust
+fn foo() -> Result<i32>┃ { Ok(42i32) }
+```
+
+#### After
+```rust
+fn foo() -> i32 { 42i32 }
+```
+
+
+### `unwrap_tuple`
+**Source:**  [unwrap_tuple.rs](crates/ide-assists/src/handlers/unwrap_tuple.rs#8) 
+
+Unwrap the tuple to different variables.
+
+#### Before
+```rust
+fn main() {
+    ┃let (foo, bar) = ("Foo", "Bar");
+}
+```
+
+#### After
+```rust
+fn main() {
+    let foo = "Foo";
+    let bar = "Bar";
+}
+```
+
+
+### `wrap_return_type_in_option`
+**Source:**  [wrap_return_type.rs](crates/ide-assists/src/handlers/wrap_return_type.rs#16) 
+
+Wrap the function's return type into Option.
+
+#### Before
+```rust
+fn foo() -> i32┃ { 42i32 }
+```
+
+#### After
+```rust
+fn foo() -> Option<i32> { Some(42i32) }
+```
+
+
+### `wrap_return_type_in_result`
+**Source:**  [wrap_return_type.rs](crates/ide-assists/src/handlers/wrap_return_type.rs#29) 
+
+Wrap the function's return type into Result.
+
+#### Before
+```rust
+fn foo() -> i32┃ { 42i32 }
+```
+
+#### After
+```rust
+fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }
+```
+
+
+### `wrap_unwrap_cfg_attr`
+**Source:**  [wrap_unwrap_cfg_attr.rs](crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs#12) 
+
+Wraps an attribute to a cfg_attr attribute or unwraps a cfg_attr attribute to the inner attributes.
+
+#### Before
+```rust
+#[derive┃(Debug)]
+struct S {
+   field: i32
+}
+```
+
+#### After
+```rust
+#[cfg_attr(┃, derive(Debug))]
+struct S {
+   field: i32
+}
+```
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 55678926609..0c6674b1408 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -470,9 +470,9 @@ The warnings will be indicated by a blue squiggly underline in code
 and a blue icon in the `Problems Panel`.
 
 
-**rust-analyzer.files.excludeDirs** (default: [])
+**rust-analyzer.files.exclude** (default: [])
 
- These directories will be ignored by rust-analyzer. They are
+ These paths (file/directories) will be ignored by rust-analyzer. They are
 relative to the workspace root, and globs are not supported. You may
 also need to add the folders to Code's `files.watcherExclude`.
 
diff --git a/src/tools/rust-analyzer/docs/book/src/diagnostics_generated.md b/src/tools/rust-analyzer/docs/book/src/diagnostics_generated.md
new file mode 100644
index 00000000000..d34c459ad02
--- /dev/null
+++ b/src/tools/rust-analyzer/docs/book/src/diagnostics_generated.md
@@ -0,0 +1,516 @@
+//! Generated by `cargo xtask codegen diagnostics-docs`, do not edit by hand.
+
+#### attribute-expansion-disabled
+
+Source:  [macro_error.rs](crates/ide-diagnostics/src/handlers/macro_error.rs#7) 
+
+
+This diagnostic is shown for attribute proc macros when attribute expansions have been disabled.
+
+
+
+
+#### await-outside-of-async
+
+Source:  [await_outside_of_async.rs](crates/ide-diagnostics/src/handlers/await_outside_of_async.rs#3) 
+
+
+This diagnostic is triggered if the `await` keyword is used outside of an async function or block
+
+
+
+
+#### break-outside-of-loop
+
+Source:  [break_outside_of_loop.rs](crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs#3) 
+
+
+This diagnostic is triggered if the `break` keyword is used outside of a loop.
+
+
+
+
+#### cast-to-unsized
+
+Source:  [invalid_cast.rs](crates/ide-diagnostics/src/handlers/invalid_cast.rs#106) 
+
+
+This diagnostic is triggered when casting to an unsized type
+
+
+
+
+#### expected-function
+
+Source:  [expected_function.rs](crates/ide-diagnostics/src/handlers/expected_function.rs#5) 
+
+
+This diagnostic is triggered if a call is made on something that is not callable.
+
+
+
+
+#### generic-args-prohibited
+
+Source:  [generic_args_prohibited.rs](crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs#10) 
+
+
+This diagnostic is shown when generic arguments are provided for a type that does not accept
+generic arguments.
+
+
+
+
+#### inactive-code
+
+Source:  [inactive_code.rs](crates/ide-diagnostics/src/handlers/inactive_code.rs#6) 
+
+
+This diagnostic is shown for code with inactive `#[cfg]` attributes.
+
+
+
+
+#### incoherent-impl
+
+Source:  [incoherent_impl.rs](crates/ide-diagnostics/src/handlers/incoherent_impl.rs#6) 
+
+
+This diagnostic is triggered if the targe type of an impl is from a foreign crate.
+
+
+
+
+#### incorrect-ident-case
+
+Source:  [incorrect_case.rs](crates/ide-diagnostics/src/handlers/incorrect_case.rs#13) 
+
+
+This diagnostic is triggered if an item name doesn't follow [Rust naming convention](https://doc.rust-lang.org/1.0.0/style/style/naming/README.html).
+
+
+
+
+#### invalid-cast
+
+Source:  [invalid_cast.rs](crates/ide-diagnostics/src/handlers/invalid_cast.rs#18) 
+
+
+This diagnostic is triggered if the code contains an illegal cast
+
+
+
+
+#### invalid-derive-target
+
+Source:  [invalid_derive_target.rs](crates/ide-diagnostics/src/handlers/invalid_derive_target.rs#3) 
+
+
+This diagnostic is shown when the derive attribute is used on an item other than a `struct`,
+`enum` or `union`.
+
+
+
+
+#### macro-def-error
+
+Source:  [macro_error.rs](crates/ide-diagnostics/src/handlers/macro_error.rs#24) 
+
+
+This diagnostic is shown for macro expansion errors.
+
+
+
+
+#### macro-error
+
+Source:  [macro_error.rs](crates/ide-diagnostics/src/handlers/macro_error.rs#3) 
+
+
+This diagnostic is shown for macro expansion errors.
+
+
+
+
+#### malformed-derive
+
+Source:  [malformed_derive.rs](crates/ide-diagnostics/src/handlers/malformed_derive.rs#3) 
+
+
+This diagnostic is shown when the derive attribute has invalid input.
+
+
+
+
+#### mismatched-arg-count
+
+Source:  [mismatched_arg_count.rs](crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs#31) 
+
+
+This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
+
+
+
+
+#### mismatched-tuple-struct-pat-arg-count
+
+Source:  [mismatched_arg_count.rs](crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs#11) 
+
+
+This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
+
+
+
+
+#### missing-fields
+
+Source:  [missing_fields.rs](crates/ide-diagnostics/src/handlers/missing_fields.rs#19) 
+
+
+This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
+
+Example:
+
+```rust
+struct A { a: u8, b: u8 }
+
+let a = A { a: 10 };
+```
+
+
+
+
+#### missing-match-arm
+
+Source:  [missing_match_arms.rs](crates/ide-diagnostics/src/handlers/missing_match_arms.rs#3) 
+
+
+This diagnostic is triggered if `match` block is missing one or more match arms.
+
+
+
+
+#### missing-unsafe
+
+Source:  [missing_unsafe.rs](crates/ide-diagnostics/src/handlers/missing_unsafe.rs#10) 
+
+
+This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block.
+
+
+
+
+#### moved-out-of-ref
+
+Source:  [moved_out_of_ref.rs](crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs#4) 
+
+
+This diagnostic is triggered on moving non copy things out of references.
+
+
+
+
+#### need-mut
+
+Source:  [mutability_errors.rs](crates/ide-diagnostics/src/handlers/mutability_errors.rs#8) 
+
+
+This diagnostic is triggered on mutating an immutable variable.
+
+
+
+
+#### no-such-field
+
+Source:  [no_such_field.rs](crates/ide-diagnostics/src/handlers/no_such_field.rs#12) 
+
+
+This diagnostic is triggered if created structure does not have field provided in record.
+
+
+
+
+#### non-exhaustive-let
+
+Source:  [non_exhaustive_let.rs](crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs#3) 
+
+
+This diagnostic is triggered if a `let` statement without an `else` branch has a non-exhaustive
+pattern.
+
+
+
+
+#### private-assoc-item
+
+Source:  [private_assoc_item.rs](crates/ide-diagnostics/src/handlers/private_assoc_item.rs#3) 
+
+
+This diagnostic is triggered if the referenced associated item is not visible from the current
+module.
+
+
+
+
+#### private-field
+
+Source:  [private_field.rs](crates/ide-diagnostics/src/handlers/private_field.rs#3) 
+
+
+This diagnostic is triggered if the accessed field is not visible from the current module.
+
+
+
+
+#### proc-macro-disabled
+
+Source:  [macro_error.rs](crates/ide-diagnostics/src/handlers/macro_error.rs#11) 
+
+
+This diagnostic is shown for proc macros that have been specifically disabled via `rust-analyzer.procMacro.ignored`.
+
+
+
+
+#### remove-trailing-return
+
+Source:  [remove_trailing_return.rs](crates/ide-diagnostics/src/handlers/remove_trailing_return.rs#8) 
+
+
+This diagnostic is triggered when there is a redundant `return` at the end of a function
+or closure.
+
+
+
+
+#### remove-unnecessary-else
+
+Source:  [remove_unnecessary_else.rs](crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs#17) 
+
+
+This diagnostic is triggered when there is an `else` block for an `if` expression whose
+then branch diverges (e.g. ends with a `return`, `continue`, `break` e.t.c).
+
+
+
+
+#### replace-filter-map-next-with-find-map
+
+Source:  [replace_filter_map_next_with_find_map.rs](crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs#11) 
+
+
+This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`.
+
+
+
+
+#### trait-impl-incorrect-safety
+
+Source:  [trait_impl_incorrect_safety.rs](crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs#6) 
+
+
+Diagnoses incorrect safety annotations of trait impls.
+
+
+
+
+#### trait-impl-missing-assoc_item
+
+Source:  [trait_impl_missing_assoc_item.rs](crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs#7) 
+
+
+Diagnoses missing trait items in a trait impl.
+
+
+
+
+#### trait-impl-orphan
+
+Source:  [trait_impl_orphan.rs](crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs#5) 
+
+
+Only traits defined in the current crate can be implemented for arbitrary types
+
+
+
+
+#### trait-impl-redundant-assoc_item
+
+Source:  [trait_impl_redundant_assoc_item.rs](crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs#12) 
+
+
+Diagnoses redundant trait items in a trait impl.
+
+
+
+
+#### type-mismatch
+
+Source:  [type_mismatch.rs](crates/ide-diagnostics/src/handlers/type_mismatch.rs#20) 
+
+
+This diagnostic is triggered when the type of an expression or pattern does not match
+the expected type.
+
+
+
+
+#### typed-hole
+
+Source:  [typed_hole.rs](crates/ide-diagnostics/src/handlers/typed_hole.rs#18) 
+
+
+This diagnostic is triggered when an underscore expression is used in an invalid position.
+
+
+
+
+#### undeclared-label
+
+Source:  [undeclared_label.rs](crates/ide-diagnostics/src/handlers/undeclared_label.rs#3) 
+
+
+
+
+
+
+#### unimplemented-builtin-macro
+
+Source:  [unimplemented_builtin_macro.rs](crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs#3) 
+
+
+This diagnostic is shown for builtin macros which are not yet implemented by rust-analyzer
+
+
+
+
+#### unlinked-file
+
+Source:  [unlinked_file.rs](crates/ide-diagnostics/src/handlers/unlinked_file.rs#20) 
+
+
+This diagnostic is shown for files that are not included in any crate, or files that are part of
+crates rust-analyzer failed to discover. The file will not have IDE features available.
+
+
+
+
+#### unnecessary-braces
+
+Source:  [useless_braces.rs](crates/ide-diagnostics/src/handlers/useless_braces.rs#9) 
+
+
+Diagnostic for unnecessary braces in `use` items.
+
+
+
+
+#### unreachable-label
+
+Source:  [unreachable_label.rs](crates/ide-diagnostics/src/handlers/unreachable_label.rs#3) 
+
+
+
+
+
+
+#### unresolved-assoc-item
+
+Source:  [unresolved_assoc_item.rs](crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs#3) 
+
+
+This diagnostic is triggered if the referenced associated item does not exist.
+
+
+
+
+#### unresolved-extern-crate
+
+Source:  [unresolved_extern_crate.rs](crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs#3) 
+
+
+This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate.
+
+
+
+
+#### unresolved-field
+
+Source:  [unresolved_field.rs](crates/ide-diagnostics/src/handlers/unresolved_field.rs#23) 
+
+
+This diagnostic is triggered if a field does not exist on a given type.
+
+
+
+
+#### unresolved-ident
+
+Source:  [unresolved_ident.rs](crates/ide-diagnostics/src/handlers/unresolved_ident.rs#3) 
+
+
+This diagnostic is triggered if an expr-position ident is invalid.
+
+
+
+
+#### unresolved-import
+
+Source:  [unresolved_import.rs](crates/ide-diagnostics/src/handlers/unresolved_import.rs#3) 
+
+
+This diagnostic is triggered if rust-analyzer is unable to resolve a path in
+a `use` declaration.
+
+
+
+
+#### unresolved-macro-call
+
+Source:  [unresolved_macro_call.rs](crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs#3) 
+
+
+This diagnostic is triggered if rust-analyzer is unable to resolve the path
+to a macro in a macro invocation.
+
+
+
+
+#### unresolved-method
+
+Source:  [unresolved_method.rs](crates/ide-diagnostics/src/handlers/unresolved_method.rs#15) 
+
+
+This diagnostic is triggered if a method does not exist on a given type.
+
+
+
+
+#### unresolved-module
+
+Source:  [unresolved_module.rs](crates/ide-diagnostics/src/handlers/unresolved_module.rs#8) 
+
+
+This diagnostic is triggered if rust-analyzer is unable to discover referred module.
+
+
+
+
+#### unused-mut
+
+Source:  [mutability_errors.rs](crates/ide-diagnostics/src/handlers/mutability_errors.rs#62) 
+
+
+This diagnostic is triggered when a mutable variable isn't actually mutated.
+
+
+
+
+#### unused-variables
+
+Source:  [unused_variables.rs](crates/ide-diagnostics/src/handlers/unused_variables.rs#13) 
+
+
+This diagnostic is triggered when a local variable is not used.
+
+
diff --git a/src/tools/rust-analyzer/docs/book/src/features_generated.md b/src/tools/rust-analyzer/docs/book/src/features_generated.md
new file mode 100644
index 00000000000..2c5829b1f54
--- /dev/null
+++ b/src/tools/rust-analyzer/docs/book/src/features_generated.md
@@ -0,0 +1,940 @@
+//! Generated by `cargo xtask codegen feature-docs`, do not edit by hand.
+
+### Annotations
+**Source:**  [annotations.rs](crates/ide/src/annotations.rs#19) 
+
+Provides user with annotations above items for looking up references or impl blocks
+and running/debugging binaries.
+
+![Annotations](https://user-images.githubusercontent.com/48062697/113020672-b7c34f00-917a-11eb-8f6e-858735660a0e.png)
+
+
+### Auto Import
+**Source:**  [auto_import.rs](crates/ide-assists/src/handlers/auto_import.rs#15) 
+
+Using the `auto-import` assist it is possible to insert missing imports for unresolved items.
+When inserting an import it will do so in a structured manner by keeping imports grouped,
+separated by a newline in the following order:
+
+- `std` and `core`
+- External Crates
+- Current Crate, paths prefixed by `crate`
+- Current Module, paths prefixed by `self`
+- Super Module, paths prefixed by `super`
+
+Example:
+```rust
+use std::fs::File;
+
+use itertools::Itertools;
+use syntax::ast;
+
+use crate::utils::insert_use;
+
+use self::auto_import;
+
+use super::AssistContext;
+```
+
+#### Import Granularity
+
+It is possible to configure how use-trees are merged with the `imports.granularity.group` setting.
+It has the following configurations:
+
+- `crate`: Merge imports from the same crate into a single use statement. This kind of
+ nesting is only supported in Rust versions later than 1.24.
+- `module`: Merge imports from the same module into a single use statement.
+- `item`: Don't merge imports at all, creating one import per item.
+- `preserve`: Do not change the granularity of any imports. For auto-import this has the same
+ effect as `item`.
+- `one`: Merge all imports into a single use statement as long as they have the same visibility
+ and attributes.
+
+In `VS Code` the configuration for this is `rust-analyzer.imports.granularity.group`.
+
+#### Import Prefix
+
+The style of imports in the same crate is configurable through the `imports.prefix` setting.
+It has the following configurations:
+
+- `crate`: This setting will force paths to be always absolute, starting with the `crate`
+ prefix, unless the item is defined outside of the current crate.
+- `self`: This setting will force paths that are relative to the current module to always
+ start with `self`. This will result in paths that always start with either `crate`, `self`,
+ `super` or an extern crate identifier.
+- `plain`: This setting does not impose any restrictions in imports.
+
+In `VS Code` the configuration for this is `rust-analyzer.imports.prefix`.
+
+![Auto Import](https://user-images.githubusercontent.com/48062697/113020673-b85be580-917a-11eb-9022-59585f35d4f8.gif)
+
+
+### Completion With Autoimport
+**Source:**  [flyimport.rs](crates/ide-completion/src/completions/flyimport.rs#20) 
+
+When completing names in the current scope, proposes additional imports from other modules or crates,
+if they can be qualified in the scope, and their name contains all symbols from the completion input.
+
+To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent.
+If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the containing is checked case-insensitively.
+
+```
+fn main() {
+    pda$0
+}
+# pub mod std { pub mod marker { pub struct PhantomData { } } }
+```
+->
+```
+use std::marker::PhantomData;
+
+fn main() {
+    PhantomData
+}
+# pub mod std { pub mod marker { pub struct PhantomData { } } }
+```
+
+Also completes associated items, that require trait imports.
+If any unresolved and/or partially-qualified path precedes the input, it will be taken into account.
+Currently, only the imports with their import path ending with the whole qualifier will be proposed
+(no fuzzy matching for qualifier).
+
+```
+mod foo {
+    pub mod bar {
+        pub struct Item;
+
+        impl Item {
+            pub const TEST_ASSOC: usize = 3;
+        }
+    }
+}
+
+fn main() {
+    bar::Item::TEST_A$0
+}
+```
+->
+```
+use foo::bar;
+
+mod foo {
+    pub mod bar {
+        pub struct Item;
+
+        impl Item {
+            pub const TEST_ASSOC: usize = 3;
+        }
+    }
+}
+
+fn main() {
+    bar::Item::TEST_ASSOC
+}
+```
+
+NOTE: currently, if an assoc item comes from a trait that's not currently imported, and it also has an unresolved and/or partially-qualified path,
+no imports will be proposed.
+
+#### Fuzzy search details
+
+To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
+(i.e. in `HashMap` in the `std::collections::HashMap` path).
+For the same reasons, avoids searching for any path imports for inputs with their length less than 2 symbols
+(but shows all associated items for any input length).
+
+#### Import configuration
+
+It is possible to configure how use-trees are merged with the `imports.granularity.group` setting.
+Mimics the corresponding behavior of the `Auto Import` feature.
+
+#### LSP and performance implications
+
+The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
+(case-sensitive) resolve client capability in its client capabilities.
+This way the server is able to defer the costly computations, doing them for a selected completion item only.
+For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
+which might be slow ergo the feature is automatically disabled.
+
+#### Feature toggle
+
+The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag.
+Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding
+capability enabled.
+
+
+### Debug ItemTree
+**Source:**  [view_item_tree.rs](crates/ide/src/view_item_tree.rs#5) 
+
+Displays the ItemTree of the currently open file, for debugging.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Debug ItemTree** |
+
+
+### Expand Macro Recursively
+**Source:**  [expand_macro.rs](crates/ide/src/expand_macro.rs#18) 
+
+Shows the full macro expansion of the macro at the current caret position.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Expand macro recursively at caret** |
+
+![Expand Macro Recursively](https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif)
+
+
+### Expand and Shrink Selection
+**Source:**  [extend_selection.rs](crates/ide/src/extend_selection.rs#15) 
+
+Extends or shrinks the current selection to the encompassing syntactic construct
+(expression, statement, item, module, etc). It works with multiple cursors.
+
+| Editor  | Shortcut |
+|---------|----------|
+| VS Code | <kbd>Alt+Shift+→</kbd>, <kbd>Alt+Shift+←</kbd> |
+
+![Expand and Shrink Selection](https://user-images.githubusercontent.com/48062697/113020651-b42fc800-917a-11eb-8a4f-cf1a07859fac.gif)
+
+
+### File Structure
+**Source:**  [file_structure.rs](crates/ide/src/file_structure.rs#26) 
+
+Provides a tree of the symbols defined in the file. Can be used to
+
+* fuzzy search symbol in a file (super useful)
+* draw breadcrumbs to describe the context around the cursor
+* draw outline of the file
+
+| Editor  | Shortcut |
+|---------|----------|
+| VS Code | <kbd>Ctrl+Shift+O</kbd> |
+
+![File Structure](https://user-images.githubusercontent.com/48062697/113020654-b42fc800-917a-11eb-8388-e7dc4d92b02e.gif)
+
+
+### Find All References
+**Source:**  [references.rs](crates/ide/src/references.rs#42) 
+
+Shows all references of the item at the cursor location
+
+| Editor  | Shortcut |
+|---------|----------|
+| VS Code | <kbd>Shift+Alt+F12</kbd> |
+
+![Find All References](https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif)
+
+
+### Folding
+**Source:**  [folding_ranges.rs](crates/ide/src/folding_ranges.rs#36) 
+
+Defines folding regions for curly braced blocks, runs of consecutive use, mod, const or static
+items, and `region` / `endregion` comment markers.
+
+
+### Format String Completion
+**Source:**  [format_like.rs](crates/ide-completion/src/completions/postfix/format_like.rs#0) 
+
+`"Result {result} is {2 + 2}"` is expanded to the `"Result {} is {}", result, 2 + 2`.
+
+The following postfix snippets are available:
+
+* `format` -> `format!(...)`
+* `panic` -> `panic!(...)`
+* `println` -> `println!(...)`
+* `log`:
+** `logd` -> `log::debug!(...)`
+** `logt` -> `log::trace!(...)`
+** `logi` -> `log::info!(...)`
+** `logw` -> `log::warn!(...)`
+** `loge` -> `log::error!(...)`
+
+![Format String Completion](https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif)
+
+
+### Go to Declaration
+**Source:**  [goto_declaration.rs](crates/ide/src/goto_declaration.rs#13) 
+
+Navigates to the declaration of an identifier.
+
+This is the same as `Go to Definition` with the following exceptions:
+- outline modules will navigate to the `mod name;` item declaration
+- trait assoc items will navigate to the assoc item of the trait declaration as opposed to the trait impl
+- fields in patterns will navigate to the field declaration of the struct, union or variant
+
+
+### Go to Definition
+**Source:**  [goto_definition.rs](crates/ide/src/goto_definition.rs#28) 
+
+Navigates to the definition of an identifier.
+
+For outline modules, this will navigate to the source file of the module.
+
+| Editor  | Shortcut |
+|---------|----------|
+| VS Code | <kbd>F12</kbd> |
+
+![Go to Definition](https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif)
+
+
+### Go to Implementation
+**Source:**  [goto_implementation.rs](crates/ide/src/goto_implementation.rs#11) 
+
+Navigates to the impl items of types.
+
+| Editor  | Shortcut |
+|---------|----------|
+| VS Code | <kbd>Ctrl+F12</kbd>
+
+![Go to Implementation](https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif)
+
+
+### Go to Type Definition
+**Source:**  [goto_type_definition.rs](crates/ide/src/goto_type_definition.rs#7) 
+
+Navigates to the type of an identifier.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **Go to Type Definition** |
+
+![Go to Type Definition](https://user-images.githubusercontent.com/48062697/113020657-b560f500-917a-11eb-9007-0f809733a338.gif)
+
+
+### Highlight Related
+**Source:**  [highlight_related.rs](crates/ide/src/highlight_related.rs#42) 
+
+Highlights constructs related to the thing under the cursor:
+
+1. if on an identifier, highlights all references to that identifier in the current file
+     * additionally, if the identifier is a trait in a where clause, type parameter trait bound or use item, highlights all references to that trait's assoc items in the corresponding scope
+1. if on an `async` or `await` token, highlights all yield points for that async context
+1. if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context
+1. if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context
+1. if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure.
+
+Note: `?`, `|` and `->` do not currently trigger this behavior in the VSCode editor.
+
+
+### Hover
+**Source:**  [hover.rs](crates/ide/src/hover.rs#116) 
+
+Shows additional information, like the type of an expression or the documentation for a definition when "focusing" code.
+Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
+
+![Hover](https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif)
+
+
+### Inlay Hints
+**Source:**  [inlay_hints.rs](crates/ide/src/inlay_hints.rs#41) 
+
+rust-analyzer shows additional information inline with the source code.
+Editors usually render this using read-only virtual text snippets interspersed with code.
+
+rust-analyzer by default shows hints for
+
+* types of local variables
+* names of function arguments
+* names of const generic parameters
+* types of chained expressions
+
+Optionally, one can enable additional hints for
+
+* return types of closure expressions
+* elided lifetimes
+* compiler inserted reborrows
+* names of generic type and lifetime parameters
+
+Note: inlay hints for function argument names are heuristically omitted to reduce noise and will not appear if
+any of the
+[following criteria](https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L92-L99)
+are met:
+
+* the parameter name is a suffix of the function's name
+* the argument is a qualified constructing or call expression where the qualifier is an ADT
+* exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
+  of argument with _ splitting it off
+* the parameter name starts with `ra_fixture`
+* the parameter name is a
+[well known name](https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L200)
+in a unary function
+* the parameter name is a
+[single character](https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L201)
+in a unary function
+
+![Inlay hints](https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png)
+
+
+### Interpret A Function, Static Or Const.
+**Source:**  [interpret.rs](crates/ide/src/interpret.rs#8) 
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Interpret** |
+
+
+### Join Lines
+**Source:**  [join_lines.rs](crates/ide/src/join_lines.rs#20) 
+
+Join selected lines into one, smartly fixing up whitespace, trailing commas, and braces.
+
+See [this gif](https://user-images.githubusercontent.com/1711539/124515923-4504e800-dde9-11eb-8d58-d97945a1a785.gif) for the cases handled specially by joined lines.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Join lines** |
+
+![Join Lines](https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif)
+
+
+### Magic Completions
+**Source:**  [lib.rs](crates/ide-completion/src/lib.rs#78) 
+
+In addition to usual reference completion, rust-analyzer provides some ✨magic✨
+completions as well:
+
+Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor
+is placed at the appropriate position. Even though `if` is easy to type, you
+still want to complete it, to get ` { }` for free! `return` is inserted with a
+space or `;` depending on the return type of the function.
+
+When completing a function call, `()` are automatically inserted. If a function
+takes arguments, the cursor is positioned inside the parenthesis.
+
+There are postfix completions, which can be triggered by typing something like
+`foo().if`. The word after `.` determines postfix completion. Possible variants are:
+
+- `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result`
+- `expr.match` -> `match expr {}`
+- `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result`
+- `expr.ref` -> `&expr`
+- `expr.refm` -> `&mut expr`
+- `expr.let` -> `let $0 = expr;`
+- `expr.lete` -> `let $1 = expr else { $0 };`
+- `expr.letm` -> `let mut $0 = expr;`
+- `expr.not` -> `!expr`
+- `expr.dbg` -> `dbg!(expr)`
+- `expr.dbgr` -> `dbg!(&expr)`
+- `expr.call` -> `(expr)`
+
+There also snippet completions:
+
+#### Expressions
+
+- `pd` -> `eprintln!(" = {:?}", );`
+- `ppd` -> `eprintln!(" = {:#?}", );`
+
+#### Items
+
+- `tfn` -> `#[test] fn feature(){}`
+- `tmod` ->
+```rust
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_name() {}
+}
+```
+
+And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities.
+Those are the additional completion options with automatic `use` import and options from all project importable items,
+fuzzy matched against the completion input.
+
+![Magic Completions](https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif)
+
+
+### Matching Brace
+**Source:**  [matching_brace.rs](crates/ide/src/matching_brace.rs#6) 
+
+If the cursor is on any brace (`<>(){}[]||`) which is a part of a brace-pair,
+moves cursor to the matching brace. It uses the actual parser to determine
+braces, so it won't confuse generics with comparisons.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Find matching brace** |
+
+![Matching Brace](https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif)
+
+
+### Memory Usage
+**Source:**  [apply_change.rs](crates/ide-db/src/apply_change.rs#43) 
+
+Clears rust-analyzer's internal database and prints memory usage statistics.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Memory Usage (Clears Database)**
+
+
+### Move Item
+**Source:**  [move_item.rs](crates/ide/src/move_item.rs#16) 
+
+Move item under cursor or selection up and down.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Move item up**
+| VS Code | **rust-analyzer: Move item down**
+
+![Move Item](https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif)
+
+
+### On Enter
+**Source:**  [on_enter.rs](crates/ide/src/typing/on_enter.rs#17) 
+
+rust-analyzer can override <kbd>Enter</kbd> key to make it smarter:
+
+- <kbd>Enter</kbd> inside triple-slash comments automatically inserts `///`
+- <kbd>Enter</kbd> in the middle or after a trailing space in `//` inserts `//`
+- <kbd>Enter</kbd> inside `//!` doc comments automatically inserts `//!`
+- <kbd>Enter</kbd> after `{` indents contents and closing `}` of single-line block
+
+This action needs to be assigned to shortcut explicitly.
+
+Note that, depending on the other installed extensions, this feature can visibly slow down typing.
+Similarly, if rust-analyzer crashes or stops responding, `Enter` might not work.
+In that case, you can still press `Shift-Enter` to insert a newline.
+
+#### VS Code
+
+Add the following to `keybindings.json`:
+```json
+{
+  "key": "Enter",
+  "command": "rust-analyzer.onEnter",
+  "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust"
+}
+````
+
+When using the Vim plugin:
+```json
+{
+  "key": "Enter",
+  "command": "rust-analyzer.onEnter",
+  "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust && vim.mode == 'Insert'"
+}
+````
+
+![On Enter](https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif)
+
+
+### On Typing Assists
+**Source:**  [typing.rs](crates/ide/src/typing.rs#42) 
+
+Some features trigger on typing certain characters:
+
+- typing `let =` tries to smartly add `;` if `=` is followed by an existing expression
+- typing `=` between two expressions adds `;` when in statement position
+- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position
+- typing `.` in a chain method call auto-indents
+- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression
+- typing `{` in a use item adds a closing `}` in the right place
+- typing `>` to complete a return type `->` will insert a whitespace after it
+
+#### VS Code
+
+Add the following to `settings.json`:
+```json
+"editor.formatOnType": true,
+```
+
+![On Typing Assists](https://user-images.githubusercontent.com/48062697/113166163-69758500-923a-11eb-81ee-eb33ec380399.gif)
+![On Typing Assists](https://user-images.githubusercontent.com/48062697/113171066-105c2000-923f-11eb-87ab-f4a263346567.gif)
+
+
+### Open Docs
+**Source:**  [doc_links.rs](crates/ide/src/doc_links.rs#118) 
+
+Retrieve a links to documentation for the given symbol.
+
+The simplest way to use this feature is via the context menu. Right-click on
+the selected item. The context menu opens. Select **Open Docs**.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Open Docs** |
+
+
+### Parent Module
+**Source:**  [parent_module.rs](crates/ide/src/parent_module.rs#14) 
+
+Navigates to the parent module of the current module.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Locate parent module** |
+
+![Parent Module](https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif)
+
+
+### Related Tests
+**Source:**  [runnables.rs](crates/ide/src/runnables.rs#202) 
+
+Provides a sneak peek of all tests where the current item is used.
+
+The simplest way to use this feature is via the context menu. Right-click on
+the selected item. The context menu opens. Select **Peek Related Tests**.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Peek Related Tests** |
+
+
+### Rename
+**Source:**  [rename.rs](crates/ide/src/rename.rs#70) 
+
+Renames the item below the cursor and all of its references
+
+| Editor  | Shortcut |
+|---------|----------|
+| VS Code | <kbd>F2</kbd> |
+
+![Rename](https://user-images.githubusercontent.com/48062697/113065582-055aae80-91b1-11eb-8ade-2b58e6d81883.gif)
+
+
+### Run
+**Source:**  [runnables.rs](crates/ide/src/runnables.rs#116) 
+
+Shows a popup suggesting to run a test/benchmark/binary **at the current cursor
+location**. Super useful for repeatedly running just a single test. Do bind this
+to a shortcut!
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Run** |
+
+![Run](https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif)
+
+
+### Semantic Syntax Highlighting
+**Source:**  [syntax_highlighting.rs](crates/ide/src/syntax_highlighting.rs#68) 
+
+rust-analyzer highlights the code semantically.
+For example, `Bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait.
+rust-analyzer does not specify colors directly, instead it assigns a tag (like `struct`) and a set of modifiers (like `declaration`) to each token.
+It's up to the client to map those to specific colors.
+
+The general rule is that a reference to an entity gets colored the same way as the entity itself.
+We also give special modifier for `mut` and `&mut` local variables.
+
+
+#### Token Tags
+
+Rust-analyzer currently emits the following token tags:
+
+- For items:
+
+|           |                                |
+|-----------|--------------------------------|
+| attribute |  Emitted for attribute macros. |
+|enum| Emitted for enums. |
+|function| Emitted for free-standing functions. |
+|derive| Emitted for derive macros. |
+|macro| Emitted for function-like macros. |
+|method| Emitted for associated functions, also knowns as methods. |
+|namespace| Emitted for modules. |
+|struct| Emitted for structs.|
+|trait| Emitted for traits.|
+|typeAlias| Emitted for type aliases and `Self` in `impl`s.|
+|union| Emitted for unions.|
+
+- For literals:
+
+|           |                                |
+|-----------|--------------------------------|
+| boolean|  Emitted for the boolean literals `true` and `false`.|
+| character| Emitted for character literals.|
+| number| Emitted for numeric literals.|
+| string| Emitted for string literals.|
+| escapeSequence| Emitted for escaped sequences inside strings like `\n`.|
+| formatSpecifier| Emitted for format specifiers `{:?}` in `format!`-like macros.|
+
+- For operators:
+
+|           |                                |
+|-----------|--------------------------------|
+|operator| Emitted for general operators.|
+|arithmetic| Emitted for the arithmetic operators `+`, `-`, `*`, `/`, `+=`, `-=`, `*=`, `/=`.|
+|bitwise| Emitted for the bitwise operators `|`, `&`, `!`, `^`, `|=`, `&=`, `^=`.|
+|comparison| Emitted for the comparison oerators `>`, `<`, `==`, `>=`, `<=`, `!=`.|
+|logical| Emitted for the logical operatos `||`, `&&`, `!`.|
+
+- For punctuation:
+
+|           |                                |
+|-----------|--------------------------------|
+|punctuation| Emitted for general punctuation.|
+|attributeBracket| Emitted for attribute invocation brackets, that is the `#[` and `]` tokens.|
+|angle| Emitted for `<>` angle brackets.|
+|brace| Emitted for `{}` braces.|
+|bracket| Emitted for `[]` brackets.|
+|parenthesis| Emitted for `()` parentheses.|
+|colon| Emitted for the `:` token.|
+|comma| Emitted for the `,` token.|
+|dot| Emitted for the `.` token.|
+|semi| Emitted for the `;` token.|
+|macroBang| Emitted for the `!` token in macro calls.|
+
+-
+
+|           |                                |
+|-----------|--------------------------------|
+|builtinAttribute| Emitted for names to builtin attributes in attribute path, the `repr` in `#[repr(u8)]` for example.|
+|builtinType| Emitted for builtin types like `u32`, `str` and `f32`.|
+|comment| Emitted for comments.|
+|constParameter| Emitted for const parameters.|
+|deriveHelper| Emitted for derive helper attributes.|
+|enumMember| Emitted for enum variants.|
+|generic| Emitted for generic tokens that have no mapping.|
+|keyword| Emitted for keywords.|
+|label| Emitted for labels.|
+|lifetime| Emitted for lifetimes.|
+|parameter| Emitted for non-self function parameters.|
+|property| Emitted for struct and union fields.|
+|selfKeyword| Emitted for the self function parameter and self path-specifier.|
+|selfTypeKeyword| Emitted for the Self type parameter.|
+|toolModule| Emitted for tool modules.|
+|typeParameter| Emitted for type parameters.|
+|unresolvedReference| Emitted for unresolved references, names that rust-analyzer can't find the definition of.|
+|variable| Emitted for locals, constants and statics.|
+
+
+#### Token Modifiers
+
+Token modifiers allow to style some elements in the source code more precisely.
+
+Rust-analyzer currently emits the following token modifiers:
+
+|           |                                |
+|-----------|--------------------------------|
+|async| Emitted for async functions and the `async` and `await` keywords.|
+|attribute| Emitted for tokens inside attributes.|
+|callable| Emitted for locals whose types implements one of the `Fn*` traits.|
+|constant| Emitted for const.|
+|consuming| Emitted for locals that are being consumed when use in a function call.|
+|controlFlow| Emitted for control-flow related tokens, this includes th `?` operator.|
+|crateRoot| Emitted for crate names, like `serde` and `crate.|
+|declaration| Emitted for names of definitions, like `foo` in `fn foo(){}`.|
+|defaultLibrary| Emitted for items from built-in crates (std, core, allc, test and proc_macro).|
+|documentation| Emitted for documentation comment.|
+|injected| Emitted for doc-string injected highlighting like rust source blocks in documentation.|
+|intraDocLink| Emitted for intra doc links in doc-string.|
+|library| Emitted for items that are defined outside of the current crae.|
+|macro|  Emitted for tokens inside macro call.|
+|mutable| Emitted for mutable locals and statics as well as functions taking `&mut self`.|
+|public| Emitted for items that are from the current crate and are `pub.|
+|reference| Emitted for locals behind a reference and functions taking self` by reference.|
+|static| Emitted for "static" functions, also known as functions that d not take a `self` param, as well as statics and consts.|
+|trait| Emitted for associated trait item.|
+|unsafe| Emitted for unsafe operations, like unsafe function calls, as ell as the `unsafe` token.|
+
+![Semantic Syntax Highlighting](https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png)
+![Semantic Syntax Highlighting](https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png)
+
+
+### Show Dependency Tree
+**Source:**  [fetch_crates.rs](crates/ide/src/fetch_crates.rs#13) 
+
+Shows a view tree with all the dependencies of this project
+
+| Editor  | Panel Name |
+|---------|------------|
+| VS Code | **Rust Dependencies** |
+
+![Show Dependency Tree](https://user-images.githubusercontent.com/5748995/229394139-2625beab-f4c9-484b-84ed-ad5dee0b1e1a.png)
+
+
+### Show Syntax Tree
+**Source:**  [view_syntax_tree.rs](crates/ide/src/view_syntax_tree.rs#14) 
+
+Shows a tree view with the syntax tree of the current file
+
+| Editor  | Panel Name |
+|---------|-------------|
+| VS Code | **Rust Syntax Tree** |
+
+
+### Status
+**Source:**  [status.rs](crates/ide/src/status.rs#28) 
+
+Shows internal statistic about memory usage of rust-analyzer.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: Status** |
+
+![Status](https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif)
+
+
+### Structural Search and Replace
+**Source:**  [lib.rs](crates/ide-ssr/src/lib.rs#6) 
+
+Search and replace with named wildcards that will match any expression, type, path, pattern or item.
+The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`.
+A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement.
+Within a macro call, a placeholder will match up until whatever token follows the placeholder.
+
+All paths in both the search pattern and the replacement template must resolve in the context
+in which this command is invoked. Paths in the search pattern will then match the code if they
+resolve to the same item, even if they're written differently. For example if we invoke the
+command in the module `foo` with a pattern of `Bar`, then code in the parent module that refers
+to `foo::Bar` will match.
+
+Paths in the replacement template will be rendered appropriately for the context in which the
+replacement occurs. For example if our replacement template is `foo::Bar` and we match some
+code in the `foo` module, we'll insert just `Bar`.
+
+Inherent method calls should generally be written in UFCS form. e.g. `foo::Bar::baz($s, $a)` will
+match `$s.baz($a)`, provided the method call `baz` resolves to the method `foo::Bar::baz`. When a
+placeholder is the receiver of a method call in the search pattern (e.g. `$s.foo()`), but not in
+the replacement template (e.g. `bar($s)`), then *, & and &mut will be added as needed to mirror
+whatever autoderef and autoref was happening implicitly in the matched code.
+
+The scope of the search / replace will be restricted to the current selection if any, otherwise
+it will apply to the whole workspace.
+
+Placeholders may be given constraints by writing them as `${<name>:<constraint1>:<constraint2>...}`.
+
+Supported constraints:
+
+| Constraint    | Restricts placeholder |
+|---------------|------------------------|
+| kind(literal) | Is a literal (e.g. `42` or `"forty two"`) |
+| not(a)        | Negates the constraint `a` |
+
+Available via the command `rust-analyzer.ssr`.
+
+```rust
+// Using structural search replace command [foo($a, $b) ==>> ($a).foo($b)]
+
+// BEFORE
+String::from(foo(y + 5, z))
+
+// AFTER
+String::from((y + 5).foo(z))
+```
+
+| Editor  | Action Name |
+|---------|--------------|
+| VS Code | **rust-analyzer: Structural Search Replace** |
+
+Also available as an assist, by writing a comment containing the structural
+search and replace rule. You will only see the assist if the comment can
+be parsed as a valid structural search and replace rule.
+
+```rust
+// Place the cursor on the line below to see the assist 💡.
+// foo($a, $b) ==>> ($a).foo($b)
+```
+
+
+### User Snippet Completions
+**Source:**  [snippet.rs](crates/ide-completion/src/snippet.rs#5) 
+
+rust-analyzer allows the user to define custom (postfix)-snippets that may depend on items to be accessible for the current scope to be applicable.
+
+A custom snippet can be defined by adding it to the `rust-analyzer.completion.snippets.custom` object respectively.
+
+```json
+{
+  "rust-analyzer.completion.snippets.custom": {
+    "thread spawn": {
+      "prefix": ["spawn", "tspawn"],
+      "body": [
+        "thread::spawn(move || {",
+        "\t$0",
+        "});",
+      ],
+      "description": "Insert a thread::spawn call",
+      "requires": "std::thread",
+      "scope": "expr",
+    }
+  }
+}
+```
+
+In the example above:
+
+* `"thread spawn"` is the name of the snippet.
+
+* `prefix` defines one or more trigger words that will trigger the snippets completion.
+Using `postfix` will instead create a postfix snippet.
+
+* `body` is one or more lines of content joined via newlines for the final output.
+
+* `description` is an optional description of the snippet, if unset the snippet name will be used.
+
+* `requires` is an optional list of item paths that have to be resolvable in the current crate where the completion is rendered.
+
+
+### View Crate Graph
+**Source:**  [view_crate_graph.rs](crates/ide/src/view_crate_graph.rs#8) 
+
+Renders the currently loaded crate graph as an SVG graphic. Requires the `dot` tool, which
+is part of graphviz, to be installed.
+
+Only workspace crates are included, no crates.io dependencies or sysroot crates.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: View Crate Graph** |
+
+
+### View Hir
+**Source:**  [view_hir.rs](crates/ide/src/view_hir.rs#5) 
+
+| Editor  | Action Name |
+|---------|--------------|
+| VS Code | **rust-analyzer: View Hir**
+
+![View Hir](https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif)
+
+
+### View Memory Layout
+**Source:**  [view_memory_layout.rs](crates/ide/src/view_memory_layout.rs#74) 
+
+Displays the recursive memory layout of a datatype.
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: View Memory Layout** |
+
+
+### View Mir
+**Source:**  [view_mir.rs](crates/ide/src/view_mir.rs#5) 
+
+| Editor  | Action Name |
+|---------|-------------|
+| VS Code | **rust-analyzer: View Mir**
+
+
+### Workspace Symbol
+**Source:**  [symbol_index.rs](crates/ide-db/src/symbol_index.rs#174) 
+
+Uses fuzzy-search to find types, modules and functions by name across your
+project and dependencies. This is **the** most useful feature, which improves code
+navigation tremendously. It mostly works on top of the built-in LSP
+functionality, however `#` and `*` symbols can be used to narrow down the
+search. Specifically,
+
+- `Foo` searches for `Foo` type in the current workspace
+- `foo#` searches for `foo` function in the current workspace
+- `Foo*` searches for `Foo` type among dependencies, including `stdlib`
+- `foo#*` searches for `foo` function among dependencies
+
+That is, `#` switches from "types" to all symbols, `*` switches from the current
+workspace to dependencies.
+
+Note that filtering does not currently work in VSCode due to the editor never
+sending the special symbols to the language server. Instead, you can configure
+the filtering via the `rust-analyzer.workspace.symbol.search.scope` and
+`rust-analyzer.workspace.symbol.search.kind` settings. Symbols prefixed
+with `__` are hidden from the search results unless configured otherwise.
+
+| Editor  | Shortcut |
+|---------|-----------|
+| VS Code | <kbd>Ctrl+T</kbd>
diff --git a/src/tools/rust-analyzer/docs/book/src/installation.md b/src/tools/rust-analyzer/docs/book/src/installation.md
index 5b697e9bc33..3a4c0cf2277 100644
--- a/src/tools/rust-analyzer/docs/book/src/installation.md
+++ b/src/tools/rust-analyzer/docs/book/src/installation.md
@@ -1,19 +1,19 @@
 # Installation
 
-In theory, one should be able to just install the [`rust-analyzer`
-binary](#rust-analyzer-language-server-binary) and have it automatically
-work with any editor. We are not there yet, so some editor specific
-setup is required.
+To use rust-analyzer, you need a `rust-analyzer` binary, a text editor
+that supports LSP, and the source code of the Rust standard library.
 
-Additionally, rust-analyzer needs the sources of the standard library.
-If the source code is not present, rust-analyzer will attempt to install
-it automatically.
+If you're [using VS Code](./vs_code.html), the extension bundles a
+copy of the `rust-analyzer` binary. For other editors, you'll need to
+[install the binary](./rust_analyzer_binary.html) and [configure your
+editor](./other_editors.html).
 
-To add the sources manually, run the following command:
+## Rust Standard Library
 
-    $ rustup component add rust-src
+rust-analyzer will attempt to install the standard library source code
+automatically. You can also install it manually with `rustup`.
 
-## Toolchain
+    $ rustup component add rust-src
 
 Only the latest stable standard library source is officially supported
 for use with rust-analyzer. If you are using an older toolchain or have
@@ -25,620 +25,16 @@ If you are using an override in your project, you can still force
 rust-analyzer to use the stable toolchain via the environment variable
 `RUSTUP_TOOLCHAIN`. For example, with VS Code or coc-rust-analyzer:
 
-    { "rust-analyzer.server.extraEnv": { "RUSTUP_TOOLCHAIN": "stable" } }
-
-## VS Code
-
-This is the best supported editor at the moment. The rust-analyzer
-plugin for VS Code is maintained [in
-tree](https://github.com/rust-lang/rust-analyzer/tree/master/editors/code).
-
-You can install the latest release of the plugin from [the
-marketplace](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer).
-
-Note that the plugin may cause conflicts with the [previous official
-Rust
-plugin](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust).
-The latter is no longer maintained and should be uninstalled.
-
-The server binary is stored in the extension install directory, which
-starts with `rust-lang.rust-analyzer-` and is located under:
-
--   Linux: `~/.vscode/extensions`
-
--   Linux (Remote, such as WSL): `~/.vscode-server/extensions`
-
--   macOS: `~/.vscode/extensions`
-
--   Windows: `%USERPROFILE%\.vscode\extensions`
-
-As an exception, on NixOS, the extension makes a copy of the server and
-stores it under
-`~/.config/Code/User/globalStorage/rust-lang.rust-analyzer`.
-
-Note that we only support the two most recent versions of VS Code.
-
-### Updates
-
-The extension will be updated automatically as new versions become
-available. It will ask your permission to download the matching language
-server version binary if needed.
-
-#### Nightly
-
-We ship nightly releases for VS Code. To help us out by testing the
-newest code, you can enable pre-release versions in the Code extension
-page.
-
-### Manual installation
-
-Alternatively, download a VSIX corresponding to your platform from the
-[releases](https://github.com/rust-lang/rust-analyzer/releases) page.
-
-Install the extension with the `Extensions: Install from VSIX` command
-within VS Code, or from the command line via:
-
-    $ code --install-extension /path/to/rust-analyzer.vsix
-
-If you are running an unsupported platform, you can install
-`rust-analyzer-no-server.vsix` and compile or obtain a server binary.
-Copy the server anywhere, then add the path to your settings.json, for
-example:
-
-    { "rust-analyzer.server.path": "~/.local/bin/rust-analyzer-linux" }
-
-### Building From Source
-
-Both the server and the Code plugin can be installed from source:
-
-    $ git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer
-    $ cargo xtask install
-
-You’ll need Cargo, nodejs (matching a supported version of VS Code) and
-npm for this.
-
-Note that installing via `xtask install` does not work for VS Code
-Remote, instead you’ll need to install the `.vsix` manually.
-
-If you’re not using Code, you can compile and install only the LSP
-server:
-
-    $ cargo xtask install --server
-
-Make sure that `.cargo/bin` is in `$PATH` and precedes paths where
-`rust-analyzer` may also be installed. Specifically, `rustup` includes a
-proxy called `rust-analyzer`, which can cause problems if you’re
-planning to use a source build or even a downloaded binary.
-
-## rust-analyzer Language Server Binary
-
-Other editors generally require the `rust-analyzer` binary to be in
-`$PATH`. You can download pre-built binaries from the
-[releases](https://github.com/rust-lang/rust-analyzer/releases) page.
-You will need to uncompress and rename the binary for your platform,
-e.g. from `rust-analyzer-aarch64-apple-darwin.gz` on Mac OS to
-`rust-analyzer`, make it executable, then move it into a directory in
-your `$PATH`.
-
-On Linux to install the `rust-analyzer` binary into `~/.local/bin`,
-these commands should work:
-
-    $ mkdir -p ~/.local/bin
-    $ curl -L https://github.com/rust-lang/rust-analyzer/releases/latest/download/rust-analyzer-x86_64-unknown-linux-gnu.gz | gunzip -c - > ~/.local/bin/rust-analyzer
-    $ chmod +x ~/.local/bin/rust-analyzer
-
-Make sure that `~/.local/bin` is listed in the `$PATH` variable and use
-the appropriate URL if you’re not on a `x86-64` system.
-
-You don’t have to use `~/.local/bin`, any other path like `~/.cargo/bin`
-or `/usr/local/bin` will work just as well.
-
-Alternatively, you can install it from source using the command below.
-You’ll need the latest stable version of the Rust toolchain.
-
-    $ git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer
-    $ cargo xtask install --server
-
-If your editor can’t find the binary even though the binary is on your
-`$PATH`, the likely explanation is that it doesn’t see the same `$PATH`
-as the shell, see [this
-issue](https://github.com/rust-lang/rust-analyzer/issues/1811). On Unix,
-running the editor from a shell or changing the `.desktop` file to set
-the environment should help.
-
-### rustup
-
-`rust-analyzer` is available in `rustup`:
-
-    $ rustup component add rust-analyzer
-
-### Arch Linux
-
-The `rust-analyzer` binary can be installed from the repos or AUR (Arch
-User Repository):
-
--   [`rust-analyzer`](https://www.archlinux.org/packages/extra/x86_64/rust-analyzer/)
-    (built from latest tagged source)
-
--   [`rust-analyzer-git`](https://aur.archlinux.org/packages/rust-analyzer-git)
-    (latest Git version)
-
-Install it with pacman, for example:
-
-    $ pacman -S rust-analyzer
-
-### Gentoo Linux
-
-`rust-analyzer` is installed when the `rust-analyzer` use flag is set for dev-lang/rust or dev-lang/rust-bin. You also need to set the `rust-src` use flag.
-
-### macOS
-
-The `rust-analyzer` binary can be installed via
-[Homebrew](https://brew.sh/).
-
-    $ brew install rust-analyzer
-
-### Windows
-
-It is recommended to install the latest Microsoft Visual C++ Redistributable prior to installation.
-Download links can be found
-[here](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist).
-
-## VS Code or VSCodium in Flatpak
-
-Setting up `rust-analyzer` with a Flatpak version of Code is not trivial
-because of the Flatpak sandbox. While the sandbox can be disabled for
-some directories, `/usr/bin` will always be mounted under
-`/run/host/usr/bin`. This prevents access to the system’s C compiler, a
-system-wide installation of Rust, or any other libraries you might want
-to link to. Some compilers and libraries can be acquired as Flatpak
-SDKs, such as `org.freedesktop.Sdk.Extension.rust-stable` or
-`org.freedesktop.Sdk.Extension.llvm15`.
-
-If you use a Flatpak SDK for Rust, it must be in your `PATH`:
-
- * install the SDK extensions with `flatpak install org.freedesktop.Sdk.Extension.{llvm15,rust-stable}//23.08`
- * enable SDK extensions in the editor with the environment variable `FLATPAK_ENABLE_SDK_EXT=llvm15,rust-stable` (this can be done using flatseal or `flatpak override`)
-
-If you want to use Flatpak in combination with `rustup`, the following
-steps might help:
-
--   both Rust and `rustup` have to be installed using
-    <https://rustup.rs>. Distro packages *will not* work.
-
--   you need to launch Code, open a terminal and run `echo $PATH`
-
--   using
-    [Flatseal](https://flathub.org/apps/details/com.github.tchx84.Flatseal),
-    you must add an environment variable called `PATH`. Set its value to
-    the output from above, appending `:~/.cargo/bin`, where `~` is the
-    path to your home directory. You must replace `~`, as it won’t be
-    expanded otherwise.
-
--   while Flatseal is open, you must enable access to "All user files"
-
-A C compiler should already be available via `org.freedesktop.Sdk`. Any
-other tools or libraries you will need to acquire from Flatpak.
-
-## Emacs
-
-Prerequisites: You have installed the [`rust-analyzer`
-binary](#rust-analyzer-language-server-binary).
-
-To use `rust-analyzer`, you need to install and enable one of the two
-popular LSP client implementations for Emacs,
-[Eglot](https://github.com/joaotavora/eglot) or [LSP
-Mode](https://github.com/emacs-lsp/lsp-mode). Both enable
-`rust-analyzer` by default in rust buffers if it is available.
-
-### Eglot
-
-Eglot is the more minimalistic and lightweight LSP client for Emacs,
-integrates well with existing Emacs functionality and is built into
-Emacs starting from release 29.
-
-After installing Eglot, e.g. via `M-x package-install` (not needed from
-Emacs 29), you can enable it via the `M-x eglot` command or load it
-automatically in `rust-mode` via
-
-    (add-hook 'rust-mode-hook 'eglot-ensure)
-
-To enable clippy, you will need to configure the initialization options
-to pass the `check.command` setting.
-
-    (add-to-list 'eglot-server-programs
-                 '((rust-ts-mode rust-mode) .
-                   ("rust-analyzer" :initializationOptions (:check (:command "clippy")))))
-
-For more detailed instructions and options see the [Eglot
-manual](https://joaotavora.github.io/eglot) (also available from Emacs
-via `M-x info`) and the [Eglot
-readme](https://github.com/joaotavora/eglot/blob/master/README.md).
-
-Eglot does not support the rust-analyzer extensions to the
-language-server protocol and does not aim to do so in the future. The
-[eglot-x](https://github.com/nemethf/eglot-x#rust-analyzer-extensions)
-package adds experimental support for those LSP extensions.
-
-### LSP Mode
-
-LSP-mode is the original LSP-client for emacs. Compared to Eglot it has
-a larger codebase and supports more features, like LSP protocol
-extensions. With extension packages like [LSP
-UI](https://github.com/emacs-lsp/lsp-mode) it offers a lot of visual
-eyecandy. Further it integrates well with [DAP
-mode](https://github.com/emacs-lsp/dap-mode) for support of the Debug
-Adapter Protocol.
-
-You can install LSP-mode via `M-x package-install` and then run it via
-the `M-x lsp` command or load it automatically in rust buffers with
-
-    (add-hook 'rust-mode-hook 'lsp-deferred)
-
-For more information on how to set up LSP mode and its extension package
-see the instructions in the [LSP mode
-manual](https://emacs-lsp.github.io/lsp-mode/page/installation). Also
-see the [rust-analyzer
-section](https://emacs-lsp.github.io/lsp-mode/page/lsp-rust-analyzer/)
-for `rust-analyzer` specific options and commands, which you can
-optionally bind to keys.
-
-Note the excellent
-[guide](https://robert.kra.hn/posts/2021-02-07_rust-with-emacs/) from
-[@rksm](https://github.com/rksm) on how to set-up Emacs for Rust
-development with LSP mode and several other packages.
-
-## Vim/Neovim
-
-Prerequisites: You have installed the [`rust-analyzer`
-binary](#rust-analyzer-language-server-binary). Not needed if the
-extension can install/update it on its own, coc-rust-analyzer is one
-example.
-
-There are several LSP client implementations for Vim or Neovim:
-
-### coc-rust-analyzer
-
-1.  Install coc.nvim by following the instructions at
-    [coc.nvim](https://github.com/neoclide/coc.nvim) (Node.js required)
-
-2.  Run `:CocInstall coc-rust-analyzer` to install
-    [coc-rust-analyzer](https://github.com/fannheyward/coc-rust-analyzer),
-    this extension implements *most* of the features supported in the
-    VSCode extension:
-
-    -   automatically install and upgrade stable/nightly releases
-
-    -   same configurations as VSCode extension,
-        `rust-analyzer.server.path`, `rust-analyzer.cargo.features` etc.
-
-    -   same commands too, `rust-analyzer.analyzerStatus`,
-        `rust-analyzer.ssr` etc.
-
-    -   inlay hints for variables and method chaining, *Neovim Only*
-
-Note: for code actions, use `coc-codeaction-cursor` and
-`coc-codeaction-selected`; `coc-codeaction` and `coc-codeaction-line`
-are unlikely to be useful.
-
-### LanguageClient-neovim
-
-1.  Install LanguageClient-neovim by following the instructions
-    [here](https://github.com/autozimu/LanguageClient-neovim)
-
-    -   The GitHub project wiki has extra tips on configuration
-
-2.  Configure by adding this to your Vim/Neovim config file (replacing
-    the existing Rust-specific line if it exists):
-
-        let g:LanguageClient_serverCommands = {
-        \ 'rust': ['rust-analyzer'],
-        \ }
-
-### YouCompleteMe
-
-Install YouCompleteMe by following the instructions
-[here](https://github.com/ycm-core/YouCompleteMe#installation).
-
-rust-analyzer is the default in ycm, it should work out of the box.
-
-### ALE
-
-To use the LSP server in [ale](https://github.com/dense-analysis/ale):
-
-    let g:ale_linters = {'rust': ['analyzer']}
-
-### nvim-lsp
-
-Neovim 0.5 has built-in language server support. For a quick start
-configuration of rust-analyzer, use
-[neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig#rust_analyzer).
-Once `neovim/nvim-lspconfig` is installed, use
-`lua require'lspconfig'.rust_analyzer.setup({})` in your `init.vim`.
-
-You can also pass LSP settings to the server:
-
-    lua << EOF
-    local lspconfig = require'lspconfig'
-
-    local on_attach = function(client)
-        require'completion'.on_attach(client)
-    end
-
-    lspconfig.rust_analyzer.setup({
-        on_attach = on_attach,
-        settings = {
-            ["rust-analyzer"] = {
-                imports = {
-                    granularity = {
-                        group = "module",
-                    },
-                    prefix = "self",
-                },
-                cargo = {
-                    buildScripts = {
-                        enable = true,
-                    },
-                },
-                procMacro = {
-                    enable = true
-                },
-            }
-        }
-    })
-    EOF
-
-If you're running Neovim 0.10 or later, you can enable inlay hints via `on_attach`:
-
-```vim
-lspconfig.rust_analyzer.setup({
-    on_attach = function(client, bufnr)
-        vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
-    end
-})
+```json
+{ "rust-analyzer.server.extraEnv": { "RUSTUP_TOOLCHAIN": "stable" } }
 ```
 
-Note that the hints are only visible after `rust-analyzer` has finished loading **and** you have to
-edit the file to trigger a re-render.
-
-See <https://sharksforarms.dev/posts/neovim-rust/> for more tips on
-getting started.
-
-Check out <https://github.com/mrcjkb/rustaceanvim> for a batteries
-included rust-analyzer setup for Neovim.
-
-### vim-lsp
-
-vim-lsp is installed by following [the plugin
-instructions](https://github.com/prabirshrestha/vim-lsp). It can be as
-simple as adding this line to your `.vimrc`:
-
-    Plug 'prabirshrestha/vim-lsp'
-
-Next you need to register the `rust-analyzer` binary. If it is avim.lspvailable
-in `$PATH`, you may want to add this to your `.vimrc`:
-
-    if executable('rust-analyzer')
-      au User lsp_setup call lsp#register_server({
-            \   'name': 'Rust Language Server',
-            \   'cmd': {server_info->['rust-analyzer']},
-            \   'whitelist': ['rust'],
-            \ })
-    endif
-
-There is no dedicated UI for the server configuration, so you would need
-to send any options as a value of the `initialization_options` field, as
-described in the [Configuration](#configuration) section. Here is an
-example of how to enable the proc-macro support:
-
-    if executable('rust-analyzer')
-      au User lsp_setup call lsp#register_server({
-            \   'name': 'Rust Language Server',
-            \   'cmd': {server_info->['rust-analyzer']},
-            \   'whitelist': ['rust'],
-            \   'initialization_options': {
-            \     'cargo': {
-            \       'buildScripts': {
-            \         'enable': v:true,
-            \       },
-            \     },
-            \     'procMacro': {
-            \       'enable': v:true,
-            \     },
-            \   },
-            \ })
-    endif
-
-## Sublime Text
-
-### Sublime Text 4:
-
--   Follow the instructions in
-    [LSP-rust-analyzer](https://github.com/sublimelsp/LSP-rust-analyzer).
-
-Install
-[LSP-file-watcher-chokidar](https://packagecontrol.io/packages/LSP-file-watcher-chokidar)
-to enable file watching (`workspace/didChangeWatchedFiles`).
-
-### Sublime Text 3:
-
--   Install the [`rust-analyzer`
-    binary](#rust-analyzer-language-server-binary).
-
--   Install the [LSP package](https://packagecontrol.io/packages/LSP).
-
--   From the command palette, run `LSP: Enable Language Server Globally`
-    and select `rust-analyzer`.
-
-If it worked, you should see "rust-analyzer, Line X, Column Y" on the
-left side of the status bar, and after waiting a bit, functionalities
-like tooltips on hovering over variables should become available.
-
-If you get an error saying `No such file or directory: 'rust-analyzer'`,
-see the [`rust-analyzer` binary](#rust-analyzer-language-server-binary)
-section on installing the language server binary.
-
-## GNOME Builder
-
-GNOME Builder 3.37.1 and newer has native `rust-analyzer` support. If
-the LSP binary is not available, GNOME Builder can install it when
-opening a Rust file.
-
-## Eclipse IDE
-
-Support for Rust development in the Eclipse IDE is provided by [Eclipse
-Corrosion](https://github.com/eclipse/corrosion). If available in PATH
-or in some standard location, `rust-analyzer` is detected and powers
-editing of Rust files without further configuration. If `rust-analyzer`
-is not detected, Corrosion will prompt you for configuration of your
-Rust toolchain and language server with a link to the *Window &gt;
-Preferences &gt; Rust* preference page; from here a button allows to
-download and configure `rust-analyzer`, but you can also reference
-another installation. You’ll need to close and reopen all .rs and Cargo
-files, or to restart the IDE, for this change to take effect.
-
-## Kate Text Editor
-
-Support for the language server protocol is built into Kate through the
-LSP plugin, which is included by default. It is preconfigured to use
-rust-analyzer for Rust sources since Kate 21.12.
-
-To change rust-analyzer config options, start from the following example
-and put it into Kate’s "User Server Settings" tab (located under the LSP
-Client settings):
-
-    {
-        "servers": {
-            "rust": {
-                "initializationOptions": {
-                    "cachePriming": {
-                        "enable": false
-                    },
-                    "check": {
-                        "allTargets": false
-                    },
-                    "checkOnSave": false
-                }
-            }
-        }
-    }
-
-Then click on apply, and restart the LSP server for your rust project.
-
-## juCi++
-
-[juCi++](https://gitlab.com/cppit/jucipp) has built-in support for the
-language server protocol, and since version 1.7.0 offers installation of
-both Rust and rust-analyzer when opening a Rust file.
-
-## Kakoune
-
-[Kakoune](https://kakoune.org/) supports LSP with the help of
-[`kak-lsp`](https://github.com/kak-lsp/kak-lsp). Follow the
-[instructions](https://github.com/kak-lsp/kak-lsp#installation) to
-install `kak-lsp`. To configure `kak-lsp`, refer to the [configuration
-section](https://github.com/kak-lsp/kak-lsp#configuring-kak-lsp) which
-is basically about copying the [configuration
-file](https://github.com/kak-lsp/kak-lsp/blob/master/kak-lsp.toml) in
-the right place (latest versions should use `rust-analyzer` by default).
-
-Finally, you need to configure Kakoune to talk to `kak-lsp` (see [Usage
-section](https://github.com/kak-lsp/kak-lsp#usage)). A basic
-configuration will only get you LSP but you can also activate inlay
-diagnostics and auto-formatting on save. The following might help you
-get all of this.
-
-    eval %sh{kak-lsp --kakoune -s $kak_session}  # Not needed if you load it with plug.kak.
-    hook global WinSetOption filetype=rust %{
-        # Enable LSP
-        lsp-enable-window
-
-        # Auto-formatting on save
-        hook window BufWritePre .* lsp-formatting-sync
-
-        # Configure inlay hints (only on save)
-        hook window -group rust-inlay-hints BufWritePost .* rust-analyzer-inlay-hints
-        hook -once -always window WinSetOption filetype=.* %{
-            remove-hooks window rust-inlay-hints
-        }
-    }
-
-## Helix
-
-[Helix](https://docs.helix-editor.com/) supports LSP by default.
-However, it won’t install `rust-analyzer` automatically. You can follow
-instructions for installing [`rust-analyzer`
-binary](#rust-analyzer-language-server-binary).
-
-## Visual Studio 2022
-
-There are multiple rust-analyzer extensions for Visual Studio 2022 on
-Windows:
-
-### rust-analyzer.vs
-
-(License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0
-International)
-
-[Visual Studio
-Marketplace](https://marketplace.visualstudio.com/items?itemName=kitamstudios.RustAnalyzer)
-
-[GitHub](https://github.com/kitamstudios/rust-analyzer/)
-
-Support for Rust development in the Visual Studio IDE is enabled by the
-[rust-analyzer](https://marketplace.visualstudio.com/items?itemName=kitamstudios.RustAnalyzer)
-package. Either click on the download link or install from IDE’s
-extension manager. For now [Visual Studio
-2022](https://visualstudio.microsoft.com/downloads/) is required. All
-editions are supported viz. Community, Professional & Enterprise. The
-package aims to provide 0-friction installation and therefore comes
-loaded with most things required including rust-analyzer binary. If
-anything it needs is missing, appropriate errors / warnings will guide
-the user. E.g. cargo.exe needs to be in path and the package will tell
-you as much. This package is under rapid active development. So if you
-encounter any issues please file it at
-[rust-analyzer.vs](https://github.com/kitamstudios/rust-analyzer/).
-
-### VS\_RustAnalyzer
-
-(License: GPL)
-
-[Visual Studio
-Marketplace](https://marketplace.visualstudio.com/items?itemName=cchharris.vsrustanalyzer)
-
-[GitHub](https://github.com/cchharris/VS-RustAnalyzer)
-
-### SourceGear Rust
-
-(License: closed source)
-
-[Visual Studio
-Marketplace](https://marketplace.visualstudio.com/items?itemName=SourceGear.SourceGearRust)
-
-[GitHub (docs, issues,
-discussions)](https://github.com/sourcegear/rust-vs-extension)
-
--   Free (no-cost)
-
--   Supports all editions of Visual Studio 2022 on Windows: Community,
-    Professional, or Enterprise
-
-## Lapce
-
-[Lapce](https://lapce.dev/) has a Rust plugin which you can install
-directly. Unfortunately, it downloads an old version of `rust-analyzer`,
-but you can set the server path under Settings.
-
 ## Crates
 
 There is a package named `ra_ap_rust_analyzer` available on
-[crates.io](https://crates.io/crates/ra_ap_rust-analyzer), for someone
-who wants to use it programmatically.
+[crates.io](https://crates.io/crates/ra_ap_rust-analyzer), for people
+who want to use rust-analyzer programmatically.
 
 For more details, see [the publish
 workflow](https://github.com/rust-lang/rust-analyzer/blob/master/.github/workflows/autopublish.yaml).
 
-## Zed
-
-[Zed](https://zed.dev) has native `rust-analyzer` support. If the LSP
-binary is not available, Zed can install it when opening a Rust file.
diff --git a/src/tools/rust-analyzer/docs/book/src/other_editors.md b/src/tools/rust-analyzer/docs/book/src/other_editors.md
new file mode 100644
index 00000000000..0a9a453e013
--- /dev/null
+++ b/src/tools/rust-analyzer/docs/book/src/other_editors.md
@@ -0,0 +1,423 @@
+# Other Editors
+
+rust-analyzer works with any editor that supports the [Language Server
+Protocol](https://microsoft.github.io/language-server-protocol/).
+
+This page assumes that you have already [installed the rust-analyzer
+binary](./rust_analyzer_binary.html).
+
+## Emacs
+
+To use `rust-analyzer`, you need to install and enable one of the two
+popular LSP client implementations for Emacs,
+[Eglot](https://github.com/joaotavora/eglot) or [LSP
+Mode](https://github.com/emacs-lsp/lsp-mode). Both enable
+`rust-analyzer` by default in Rust buffers if it is available.
+
+### Eglot
+
+Eglot is the more minimalistic and lightweight LSP client for Emacs,
+integrates well with existing Emacs functionality and is built into
+Emacs starting from release 29.
+
+After installing Eglot, e.g. via `M-x package-install` (not needed from
+Emacs 29), you can enable it via the `M-x eglot` command or load it
+automatically in `rust-mode` via
+
+```
+(add-hook 'rust-mode-hook 'eglot-ensure)
+```
+
+To enable clippy, you will need to configure the initialization options
+to pass the `check.command` setting.
+
+```
+(add-to-list 'eglot-server-programs
+             '((rust-ts-mode rust-mode) .
+               ("rust-analyzer" :initializationOptions (:check (:command "clippy")))))
+```
+
+For more detailed instructions and options see the [Eglot
+manual](https://joaotavora.github.io/eglot) (also available from Emacs
+via `M-x info`) and the [Eglot
+readme](https://github.com/joaotavora/eglot/blob/master/README.md).
+
+Eglot does not support the rust-analyzer extensions to the
+language-server protocol and does not aim to do so in the future. The
+[eglot-x](https://github.com/nemethf/eglot-x#rust-analyzer-extensions)
+package adds experimental support for those LSP extensions.
+
+### LSP Mode
+
+LSP-mode is the original LSP-client for emacs. Compared to Eglot it has
+a larger codebase and supports more features, like LSP protocol
+extensions. With extension packages like [LSP
+UI](https://github.com/emacs-lsp/lsp-mode) it offers a lot of visual
+eyecandy. Further it integrates well with [DAP
+mode](https://github.com/emacs-lsp/dap-mode) for support of the Debug
+Adapter Protocol.
+
+You can install LSP-mode via `M-x package-install` and then run it via
+the `M-x lsp` command or load it automatically in rust buffers with
+
+```
+(add-hook 'rust-mode-hook 'lsp-deferred)
+```
+
+For more information on how to set up LSP mode and its extension package
+see the instructions in the [LSP mode
+manual](https://emacs-lsp.github.io/lsp-mode/page/installation). Also
+see the [rust-analyzer
+section](https://emacs-lsp.github.io/lsp-mode/page/lsp-rust-analyzer/)
+for `rust-analyzer` specific options and commands, which you can
+optionally bind to keys.
+
+Note the excellent
+[guide](https://robert.kra.hn/posts/2021-02-07_rust-with-emacs/) from
+[@rksm](https://github.com/rksm) on how to set-up Emacs for Rust
+development with LSP mode and several other packages.
+
+## Vim/Neovim
+
+There are several LSP client implementations for Vim or Neovim:
+
+### coc-rust-analyzer
+
+1.  Install coc.nvim by following the instructions at
+    [coc.nvim](https://github.com/neoclide/coc.nvim) (Node.js required)
+
+2.  Run `:CocInstall coc-rust-analyzer` to install
+    [coc-rust-analyzer](https://github.com/fannheyward/coc-rust-analyzer),
+    this extension implements *most* of the features supported in the
+    VSCode extension:
+
+    -   automatically install and upgrade stable/nightly releases
+
+    -   same configurations as VSCode extension,
+        `rust-analyzer.server.path`, `rust-analyzer.cargo.features` etc.
+
+    -   same commands too, `rust-analyzer.analyzerStatus`,
+        `rust-analyzer.ssr` etc.
+
+    -   inlay hints for variables and method chaining, *Neovim Only*
+
+Note: coc-rust-analyzer is capable of installing or updating the
+rust-analyzer binary on its own.
+
+Note: for code actions, use `coc-codeaction-cursor` and
+`coc-codeaction-selected`; `coc-codeaction` and `coc-codeaction-line`
+are unlikely to be useful.
+
+### LanguageClient-neovim
+
+1.  Install LanguageClient-neovim by following the instructions
+    [here](https://github.com/autozimu/LanguageClient-neovim)
+
+    -   The GitHub project wiki has extra tips on configuration
+
+2.  Configure by adding this to your Vim/Neovim config file (replacing
+    the existing Rust-specific line if it exists):
+
+        let g:LanguageClient_serverCommands = {
+        \ 'rust': ['rust-analyzer'],
+        \ }
+
+### YouCompleteMe
+
+Install YouCompleteMe by following the instructions
+[here](https://github.com/ycm-core/YouCompleteMe#installation).
+
+rust-analyzer is the default in ycm, it should work out of the box.
+
+### ALE
+
+To use the LSP server in [ale](https://github.com/dense-analysis/ale):
+
+    let g:ale_linters = {'rust': ['analyzer']}
+
+### nvim-lsp
+
+Neovim 0.5 has built-in language server support. For a quick start
+configuration of rust-analyzer, use
+[neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig#rust_analyzer).
+Once `neovim/nvim-lspconfig` is installed, use
+`lua require'lspconfig'.rust_analyzer.setup({})` in your `init.vim`.
+
+You can also pass LSP settings to the server:
+
+```lua
+lua << EOF
+local lspconfig = require'lspconfig'
+
+local on_attach = function(client)
+    require'completion'.on_attach(client)
+end
+
+lspconfig.rust_analyzer.setup({
+    on_attach = on_attach,
+    settings = {
+        ["rust-analyzer"] = {
+            imports = {
+                granularity = {
+                    group = "module",
+                },
+                prefix = "self",
+            },
+            cargo = {
+                buildScripts = {
+                    enable = true,
+                },
+            },
+            procMacro = {
+                enable = true
+            },
+        }
+    }
+})
+EOF
+```
+
+If you're running Neovim 0.10 or later, you can enable inlay hints via `on_attach`:
+
+```lua
+lspconfig.rust_analyzer.setup({
+    on_attach = function(client, bufnr)
+        vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
+    end
+})
+```
+
+Note that the hints are only visible after `rust-analyzer` has finished loading **and** you have to
+edit the file to trigger a re-render.
+
+See <https://sharksforarms.dev/posts/neovim-rust/> for more tips on
+getting started.
+
+Check out <https://github.com/mrcjkb/rustaceanvim> for a batteries
+included rust-analyzer setup for Neovim.
+
+### vim-lsp
+
+vim-lsp is installed by following [the plugin
+instructions](https://github.com/prabirshrestha/vim-lsp). It can be as
+simple as adding this line to your `.vimrc`:
+
+    Plug 'prabirshrestha/vim-lsp'
+
+Next you need to register the `rust-analyzer` binary. If it is avim.lspvailable
+in `$PATH`, you may want to add this to your `.vimrc`:
+
+    if executable('rust-analyzer')
+      au User lsp_setup call lsp#register_server({
+            \   'name': 'Rust Language Server',
+            \   'cmd': {server_info->['rust-analyzer']},
+            \   'whitelist': ['rust'],
+            \ })
+    endif
+
+There is no dedicated UI for the server configuration, so you would need
+to send any options as a value of the `initialization_options` field, as
+described in the [Configuration](#configuration) section. Here is an
+example of how to enable the proc-macro support:
+
+    if executable('rust-analyzer')
+      au User lsp_setup call lsp#register_server({
+            \   'name': 'Rust Language Server',
+            \   'cmd': {server_info->['rust-analyzer']},
+            \   'whitelist': ['rust'],
+            \   'initialization_options': {
+            \     'cargo': {
+            \       'buildScripts': {
+            \         'enable': v:true,
+            \       },
+            \     },
+            \     'procMacro': {
+            \       'enable': v:true,
+            \     },
+            \   },
+            \ })
+    endif
+
+## Sublime Text
+
+### Sublime Text 4:
+
+-   Follow the instructions in
+    [LSP-rust-analyzer](https://github.com/sublimelsp/LSP-rust-analyzer).
+
+Install
+[LSP-file-watcher-chokidar](https://packagecontrol.io/packages/LSP-file-watcher-chokidar)
+to enable file watching (`workspace/didChangeWatchedFiles`).
+
+### Sublime Text 3:
+
+-   Install the [LSP package](https://packagecontrol.io/packages/LSP).
+
+-   From the command palette, run `LSP: Enable Language Server Globally`
+    and select `rust-analyzer`.
+
+If it worked, you should see "rust-analyzer, Line X, Column Y" on the
+left side of the status bar, and after waiting a bit, functionalities
+like tooltips on hovering over variables should become available.
+
+If you get an error saying `No such file or directory: 'rust-analyzer'`,
+see the [rust-analyzer binary installation](./rust_analyzer_binary.html) section.
+
+## GNOME Builder
+
+GNOME Builder 3.37.1 and newer has native `rust-analyzer` support. If
+the LSP binary is not available, GNOME Builder can install it when
+opening a Rust file.
+
+## Eclipse IDE
+
+Support for Rust development in the Eclipse IDE is provided by [Eclipse
+Corrosion](https://github.com/eclipse/corrosion). If available in PATH
+or in some standard location, `rust-analyzer` is detected and powers
+editing of Rust files without further configuration. If `rust-analyzer`
+is not detected, Corrosion will prompt you for configuration of your
+Rust toolchain and language server with a link to the *Window &gt;
+Preferences &gt; Rust* preference page; from here a button allows to
+download and configure `rust-analyzer`, but you can also reference
+another installation. You’ll need to close and reopen all .rs and Cargo
+files, or to restart the IDE, for this change to take effect.
+
+## Kate Text Editor
+
+Support for the language server protocol is built into Kate through the
+LSP plugin, which is included by default. It is preconfigured to use
+rust-analyzer for Rust sources since Kate 21.12.
+
+To change rust-analyzer config options, start from the following example
+and put it into Kate’s "User Server Settings" tab (located under the LSP
+Client settings):
+
+```json
+{
+    "servers": {
+        "rust": {
+            "initializationOptions": {
+                "cachePriming": {
+                    "enable": false
+                },
+                "check": {
+                    "allTargets": false
+                },
+                "checkOnSave": false
+            }
+        }
+    }
+}
+```
+
+Then click on apply, and restart the LSP server for your rust project.
+
+## juCi++
+
+[juCi++](https://gitlab.com/cppit/jucipp) has built-in support for the
+language server protocol, and since version 1.7.0 offers installation of
+both Rust and rust-analyzer when opening a Rust file.
+
+## Kakoune
+
+[Kakoune](https://kakoune.org/) supports LSP with the help of
+[`kak-lsp`](https://github.com/kak-lsp/kak-lsp). Follow the
+[instructions](https://github.com/kak-lsp/kak-lsp#installation) to
+install `kak-lsp`. To configure `kak-lsp`, refer to the [configuration
+section](https://github.com/kak-lsp/kak-lsp#configuring-kak-lsp) which
+is basically about copying the [configuration
+file](https://github.com/kak-lsp/kak-lsp/blob/master/kak-lsp.toml) in
+the right place (latest versions should use `rust-analyzer` by default).
+
+Finally, you need to configure Kakoune to talk to `kak-lsp` (see [Usage
+section](https://github.com/kak-lsp/kak-lsp#usage)). A basic
+configuration will only get you LSP but you can also activate inlay
+diagnostics and auto-formatting on save. The following might help you
+get all of this.
+
+    eval %sh{kak-lsp --kakoune -s $kak_session}  # Not needed if you load it with plug.kak.
+    hook global WinSetOption filetype=rust %{
+        # Enable LSP
+        lsp-enable-window
+
+        # Auto-formatting on save
+        hook window BufWritePre .* lsp-formatting-sync
+
+        # Configure inlay hints (only on save)
+        hook window -group rust-inlay-hints BufWritePost .* rust-analyzer-inlay-hints
+        hook -once -always window WinSetOption filetype=.* %{
+            remove-hooks window rust-inlay-hints
+        }
+    }
+
+## Helix
+
+[Helix](https://docs.helix-editor.com/) supports LSP by default.
+However, it won’t install `rust-analyzer` automatically. You can follow
+instructions for [installing the rust-analyzer
+binary](./rust_analyzer_binary.html).
+
+## Visual Studio 2022
+
+There are multiple rust-analyzer extensions for Visual Studio 2022 on
+Windows:
+
+### rust-analyzer.vs
+
+(License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0
+International)
+
+[Visual Studio
+Marketplace](https://marketplace.visualstudio.com/items?itemName=kitamstudios.RustAnalyzer)
+
+[GitHub](https://github.com/kitamstudios/rust-analyzer/)
+
+Support for Rust development in the Visual Studio IDE is enabled by the
+[rust-analyzer](https://marketplace.visualstudio.com/items?itemName=kitamstudios.RustAnalyzer)
+package. Either click on the download link or install from IDE’s
+extension manager. For now [Visual Studio
+2022](https://visualstudio.microsoft.com/downloads/) is required. All
+editions are supported viz. Community, Professional & Enterprise. The
+package aims to provide 0-friction installation and therefore comes
+loaded with most things required including rust-analyzer binary. If
+anything it needs is missing, appropriate errors / warnings will guide
+the user. E.g. cargo.exe needs to be in path and the package will tell
+you as much. This package is under rapid active development. So if you
+encounter any issues please file it at
+[rust-analyzer.vs](https://github.com/kitamstudios/rust-analyzer/).
+
+### VS RustAnalyzer
+
+(License: GPL)
+
+[Visual Studio
+Marketplace](https://marketplace.visualstudio.com/items?itemName=cchharris.vsrustanalyzer)
+
+[GitHub](https://github.com/cchharris/VS-RustAnalyzer)
+
+### SourceGear Rust
+
+(License: closed source)
+
+[Visual Studio
+Marketplace](https://marketplace.visualstudio.com/items?itemName=SourceGear.SourceGearRust)
+
+[GitHub (docs, issues,
+discussions)](https://github.com/sourcegear/rust-vs-extension)
+
+-   Free (no-cost)
+
+-   Supports all editions of Visual Studio 2022 on Windows: Community,
+    Professional, or Enterprise
+
+## Lapce
+
+[Lapce](https://lapce.dev/) has a Rust plugin which you can install
+directly. Unfortunately, it downloads an old version of `rust-analyzer`,
+but you can set the server path under Settings.
+
+## Zed
+
+[Zed](https://zed.dev) has native `rust-analyzer` support. If the
+rust-analyzer binary is not available, Zed can install it when opening
+a Rust file.
diff --git a/src/tools/rust-analyzer/docs/book/src/rust_analyzer_binary.md b/src/tools/rust-analyzer/docs/book/src/rust_analyzer_binary.md
new file mode 100644
index 00000000000..c7ac3087ced
--- /dev/null
+++ b/src/tools/rust-analyzer/docs/book/src/rust_analyzer_binary.md
@@ -0,0 +1,74 @@
+# rust-analyzer Binary
+
+Text editors require the `rust-analyzer` binary to be in
+`$PATH`. You can download pre-built binaries from the
+[releases](https://github.com/rust-lang/rust-analyzer/releases) page.
+You will need to uncompress and rename the binary for your platform,
+e.g. from `rust-analyzer-aarch64-apple-darwin.gz` on Mac OS to
+`rust-analyzer`, make it executable, then move it into a directory in
+your `$PATH`.
+
+On Linux to install the `rust-analyzer` binary into `~/.local/bin`,
+these commands should work:
+
+    $ mkdir -p ~/.local/bin
+    $ curl -L https://github.com/rust-lang/rust-analyzer/releases/latest/download/rust-analyzer-x86_64-unknown-linux-gnu.gz | gunzip -c - > ~/.local/bin/rust-analyzer
+    $ chmod +x ~/.local/bin/rust-analyzer
+
+Make sure that `~/.local/bin` is listed in the `$PATH` variable and use
+the appropriate URL if you’re not on a `x86-64` system.
+
+You don’t have to use `~/.local/bin`, any other path like `~/.cargo/bin`
+or `/usr/local/bin` will work just as well.
+
+Alternatively, you can install it from source using the command below.
+You’ll need the latest stable version of the Rust toolchain.
+
+    $ git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer
+    $ cargo xtask install --server
+
+If your editor can’t find the binary even though the binary is on your
+`$PATH`, the likely explanation is that it doesn’t see the same `$PATH`
+as the shell, see [this
+issue](https://github.com/rust-lang/rust-analyzer/issues/1811). On Unix,
+running the editor from a shell or changing the `.desktop` file to set
+the environment should help.
+
+### rustup
+
+`rust-analyzer` is available in `rustup`:
+
+    $ rustup component add rust-analyzer
+
+### Arch Linux
+
+The `rust-analyzer` binary can be installed from the repos or AUR (Arch
+User Repository):
+
+-   [`rust-analyzer`](https://www.archlinux.org/packages/extra/x86_64/rust-analyzer/)
+    (built from latest tagged source)
+
+-   [`rust-analyzer-git`](https://aur.archlinux.org/packages/rust-analyzer-git)
+    (latest Git version)
+
+Install it with pacman, for example:
+
+    $ pacman -S rust-analyzer
+
+### Gentoo Linux
+
+`rust-analyzer` is installed when the `rust-analyzer` use flag is set for dev-lang/rust or dev-lang/rust-bin. You also need to set the `rust-src` use flag.
+
+### macOS
+
+The `rust-analyzer` binary can be installed via
+[Homebrew](https://brew.sh/).
+
+    $ brew install rust-analyzer
+
+### Windows
+
+It is recommended to install the latest Microsoft Visual C++ Redistributable prior to installation.
+Download links can be found
+[here](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist).
+
diff --git a/src/tools/rust-analyzer/docs/book/src/vs_code.md b/src/tools/rust-analyzer/docs/book/src/vs_code.md
new file mode 100644
index 00000000000..233b862d2c6
--- /dev/null
+++ b/src/tools/rust-analyzer/docs/book/src/vs_code.md
@@ -0,0 +1,121 @@
+# VS Code
+
+This is the best supported editor at the moment. The rust-analyzer
+plugin for VS Code is maintained [in
+tree](https://github.com/rust-lang/rust-analyzer/tree/master/editors/code).
+
+You can install the latest release of the plugin from [the
+marketplace](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer).
+
+Note that the plugin may cause conflicts with the [previous official
+Rust
+plugin](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust).
+The latter is no longer maintained and should be uninstalled.
+
+The server binary is stored in the extension install directory, which
+starts with `rust-lang.rust-analyzer-` and is located under:
+
+-   Linux: `~/.vscode/extensions`
+
+-   Linux (Remote, such as WSL): `~/.vscode-server/extensions`
+
+-   macOS: `~/.vscode/extensions`
+
+-   Windows: `%USERPROFILE%\.vscode\extensions`
+
+As an exception, on NixOS, the extension makes a copy of the server and
+stores it under
+`~/.config/Code/User/globalStorage/rust-lang.rust-analyzer`.
+
+Note that we only support the two most recent versions of VS Code.
+
+### Updates
+
+The extension will be updated automatically as new versions become
+available. It will ask your permission to download the matching language
+server version binary if needed.
+
+#### Nightly
+
+We ship nightly releases for VS Code. To help us out by testing the
+newest code, you can enable pre-release versions in the Code extension
+page.
+
+### Manual installation
+
+Alternatively, download a VSIX corresponding to your platform from the
+[releases](https://github.com/rust-lang/rust-analyzer/releases) page.
+
+Install the extension with the `Extensions: Install from VSIX` command
+within VS Code, or from the command line via:
+
+    $ code --install-extension /path/to/rust-analyzer.vsix
+
+If you are running an unsupported platform, you can install
+`rust-analyzer-no-server.vsix` and compile or obtain a server binary.
+Copy the server anywhere, then add the path to your settings.json, for
+example:
+
+```json
+{ "rust-analyzer.server.path": "~/.local/bin/rust-analyzer-linux" }
+```
+
+### Building From Source
+
+Both the server and the Code plugin can be installed from source:
+
+    $ git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer
+    $ cargo xtask install
+
+You’ll need Cargo, nodejs (matching a supported version of VS Code) and
+npm for this.
+
+Note that installing via `xtask install` does not work for VS Code
+Remote, instead you’ll need to install the `.vsix` manually.
+
+If you’re not using Code, you can compile and install only the LSP
+server:
+
+    $ cargo xtask install --server
+
+Make sure that `.cargo/bin` is in `$PATH` and precedes paths where
+`rust-analyzer` may also be installed. Specifically, `rustup` includes a
+proxy called `rust-analyzer`, which can cause problems if you’re
+planning to use a source build or even a downloaded binary.
+
+## VS Code or VSCodium in Flatpak
+
+Setting up `rust-analyzer` with a Flatpak version of Code is not trivial
+because of the Flatpak sandbox. While the sandbox can be disabled for
+some directories, `/usr/bin` will always be mounted under
+`/run/host/usr/bin`. This prevents access to the system’s C compiler, a
+system-wide installation of Rust, or any other libraries you might want
+to link to. Some compilers and libraries can be acquired as Flatpak
+SDKs, such as `org.freedesktop.Sdk.Extension.rust-stable` or
+`org.freedesktop.Sdk.Extension.llvm15`.
+
+If you use a Flatpak SDK for Rust, it must be in your `PATH`:
+
+ * install the SDK extensions with `flatpak install org.freedesktop.Sdk.Extension.{llvm15,rust-stable}//23.08`
+ * enable SDK extensions in the editor with the environment variable `FLATPAK_ENABLE_SDK_EXT=llvm15,rust-stable` (this can be done using flatseal or `flatpak override`)
+
+If you want to use Flatpak in combination with `rustup`, the following
+steps might help:
+
+-   both Rust and `rustup` have to be installed using
+    <https://rustup.rs>. Distro packages *will not* work.
+
+-   you need to launch Code, open a terminal and run `echo $PATH`
+
+-   using
+    [Flatseal](https://flathub.org/apps/details/com.github.tchx84.Flatseal),
+    you must add an environment variable called `PATH`. Set its value to
+    the output from above, appending `:~/.cargo/bin`, where `~` is the
+    path to your home directory. You must replace `~`, as it won’t be
+    expanded otherwise.
+
+-   while Flatseal is open, you must enable access to "All user files"
+
+A C compiler should already be available via `org.freedesktop.Sdk`. Any
+other tools or libraries you will need to acquire from Flatpak.
+
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index 6027f813311..86a066454a5 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -23,7 +23,7 @@
                 "@typescript-eslint/parser": "^6.0.0",
                 "@vscode/test-electron": "^2.3.8",
                 "@vscode/vsce": "^3.0.0",
-                "esbuild": "^0.18.12",
+                "esbuild": "^0.25.0",
                 "eslint": "^8.44.0",
                 "eslint-config-prettier": "^8.8.0",
                 "ovsx": "^0.8.2",
@@ -256,356 +256,429 @@
                 "node": ">=16"
             }
         },
+        "node_modules/@esbuild/aix-ppc64": {
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
+            "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
+            "cpu": [
+                "ppc64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "aix"
+            ],
+            "engines": {
+                "node": ">=18"
+            }
+        },
         "node_modules/@esbuild/android-arm": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.12.tgz",
-            "integrity": "sha512-LIxaNIQfkFZbTLb4+cX7dozHlAbAshhFE5PKdro0l+FnCpx1GDJaQ2WMcqm+ToXKMt8p8Uojk/MFRuGyz3V5Sw==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
+            "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
             "cpu": [
                 "arm"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "android"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/android-arm64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.12.tgz",
-            "integrity": "sha512-BMAlczRqC/LUt2P97E4apTBbkvS9JTJnp2DKFbCwpZ8vBvXVbNdqmvzW/OsdtI/+mGr+apkkpqGM8WecLkPgrA==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
+            "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
             "cpu": [
                 "arm64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "android"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/android-x64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.12.tgz",
-            "integrity": "sha512-zU5MyluNsykf5cOJ0LZZZjgAHbhPJ1cWfdH1ZXVMXxVMhEV0VZiZXQdwBBVvmvbF28EizeK7obG9fs+fpmS0eQ==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
+            "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
             "cpu": [
                 "x64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "android"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/darwin-arm64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.12.tgz",
-            "integrity": "sha512-zUZMep7YONnp6954QOOwEBwFX9svlKd3ov6PkxKd53LGTHsp/gy7vHaPGhhjBmEpqXEXShi6dddjIkmd+NgMsA==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
+            "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
             "cpu": [
                 "arm64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "darwin"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/darwin-x64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.12.tgz",
-            "integrity": "sha512-ohqLPc7i67yunArPj1+/FeeJ7AgwAjHqKZ512ADk3WsE3FHU9l+m5aa7NdxXr0HmN1bjDlUslBjWNbFlD9y12Q==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
+            "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
             "cpu": [
                 "x64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "darwin"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/freebsd-arm64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.12.tgz",
-            "integrity": "sha512-GIIHtQXqgeOOqdG16a/A9N28GpkvjJnjYMhOnXVbn3EDJcoItdR58v/pGN31CHjyXDc8uCcRnFWmqaJt24AYJg==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
+            "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
             "cpu": [
                 "arm64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "freebsd"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/freebsd-x64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.12.tgz",
-            "integrity": "sha512-zK0b9a1/0wZY+6FdOS3BpZcPc1kcx2G5yxxfEJtEUzVxI6n/FrC2Phsxj/YblPuBchhBZ/1wwn7AyEBUyNSa6g==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
+            "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
             "cpu": [
                 "x64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "freebsd"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/linux-arm": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.12.tgz",
-            "integrity": "sha512-y75OijvrBE/1XRrXq1jtrJfG26eHeMoqLJ2dwQNwviwTuTtHGCojsDO6BJNF8gU+3jTn1KzJEMETytwsFSvc+Q==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
+            "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
             "cpu": [
                 "arm"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "linux"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/linux-arm64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.12.tgz",
-            "integrity": "sha512-JKgG8Q/LL/9sw/iHHxQyVMoQYu3rU3+a5Z87DxC+wAu3engz+EmctIrV+FGOgI6gWG1z1+5nDDbXiRMGQZXqiw==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
+            "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
             "cpu": [
                 "arm64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "linux"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/linux-ia32": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.12.tgz",
-            "integrity": "sha512-yoRIAqc0B4lDIAAEFEIu9ttTRFV84iuAl0KNCN6MhKLxNPfzwCBvEMgwco2f71GxmpBcTtn7KdErueZaM2rEvw==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
+            "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
             "cpu": [
                 "ia32"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "linux"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/linux-loong64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.12.tgz",
-            "integrity": "sha512-qYgt3dHPVvf/MgbIBpJ4Sup/yb9DAopZ3a2JgMpNKIHUpOdnJ2eHBo/aQdnd8dJ21X/+sS58wxHtA9lEazYtXQ==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
+            "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
             "cpu": [
                 "loong64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "linux"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/linux-mips64el": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.12.tgz",
-            "integrity": "sha512-wHphlMLK4ufNOONqukELfVIbnGQJrHJ/mxZMMrP2jYrPgCRZhOtf0kC4yAXBwnfmULimV1qt5UJJOw4Kh13Yfg==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
+            "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
             "cpu": [
                 "mips64el"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "linux"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/linux-ppc64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.12.tgz",
-            "integrity": "sha512-TeN//1Ft20ZZW41+zDSdOI/Os1bEq5dbvBvYkberB7PHABbRcsteeoNVZFlI0YLpGdlBqohEpjrn06kv8heCJg==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
+            "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
             "cpu": [
                 "ppc64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "linux"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/linux-riscv64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.12.tgz",
-            "integrity": "sha512-AgUebVS4DoAblBgiB2ACQ/8l4eGE5aWBb8ZXtkXHiET9mbj7GuWt3OnsIW/zX+XHJt2RYJZctbQ2S/mDjbp0UA==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
+            "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
             "cpu": [
                 "riscv64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "linux"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/linux-s390x": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.12.tgz",
-            "integrity": "sha512-dJ3Rb3Ei2u/ysSXd6pzleGtfDdc2MuzKt8qc6ls8vreP1G3B7HInX3i7gXS4BGeVd24pp0yqyS7bJ5NHaI9ing==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
+            "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
             "cpu": [
                 "s390x"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "linux"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/linux-x64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.12.tgz",
-            "integrity": "sha512-OrNJMGQbPaVyHHcDF8ybNSwu7TDOfX8NGpXCbetwOSP6txOJiWlgQnRymfC9ocR1S0Y5PW0Wb1mV6pUddqmvmQ==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
+            "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
             "cpu": [
                 "x64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "linux"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
+            }
+        },
+        "node_modules/@esbuild/netbsd-arm64": {
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
+            "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "netbsd"
+            ],
+            "engines": {
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/netbsd-x64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.12.tgz",
-            "integrity": "sha512-55FzVCAiwE9FK8wWeCRuvjazNRJ1QqLCYGZVB6E8RuQuTeStSwotpSW4xoRGwp3a1wUsaVCdYcj5LGCASVJmMg==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
+            "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
             "cpu": [
                 "x64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "netbsd"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
+            }
+        },
+        "node_modules/@esbuild/openbsd-arm64": {
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
+            "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "openbsd"
+            ],
+            "engines": {
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/openbsd-x64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.12.tgz",
-            "integrity": "sha512-qnluf8rfb6Y5Lw2tirfK2quZOBbVqmwxut7GPCIJsM8lc4AEUj9L8y0YPdLaPK0TECt4IdyBdBD/KRFKorlK3g==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
+            "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
             "cpu": [
                 "x64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "openbsd"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/sunos-x64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.12.tgz",
-            "integrity": "sha512-+RkKpVQR7bICjTOPUpkTBTaJ4TFqQBX5Ywyd/HSdDkQGn65VPkTsR/pL4AMvuMWy+wnXgIl4EY6q4mVpJal8Kg==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
+            "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
             "cpu": [
                 "x64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "sunos"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/win32-arm64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.12.tgz",
-            "integrity": "sha512-GNHuciv0mFM7ouzsU0+AwY+7eV4Mgo5WnbhfDCQGtpvOtD1vbOiRjPYG6dhmMoFyBjj+pNqQu2X+7DKn0KQ/Gw==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
+            "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
             "cpu": [
                 "arm64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "win32"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/win32-ia32": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.12.tgz",
-            "integrity": "sha512-kR8cezhYipbbypGkaqCTWIeu4zID17gamC8YTPXYtcN3E5BhhtTnwKBn9I0PJur/T6UVwIEGYzkffNL0lFvxEw==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
+            "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
             "cpu": [
                 "ia32"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "win32"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@esbuild/win32-x64": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.12.tgz",
-            "integrity": "sha512-O0UYQVkvfM/jO8a4OwoV0mAKSJw+mjWTAd1MJd/1FCX6uiMdLmMRPK/w6e9OQ0ob2WGxzIm9va/KG0Ja4zIOgg==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
+            "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
             "cpu": [
                 "x64"
             ],
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "win32"
             ],
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/@eslint-community/eslint-utils": {
@@ -2521,40 +2594,44 @@
             }
         },
         "node_modules/esbuild": {
-            "version": "0.18.12",
-            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.12.tgz",
-            "integrity": "sha512-XuOVLDdtsDslXStStduT41op21Ytmf4/BDS46aa3xPJ7X5h2eMWBF1oAe3QjUH3bDksocNXgzGUZ7XHIBya6Tg==",
+            "version": "0.25.0",
+            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
+            "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
             "dev": true,
             "hasInstallScript": true,
+            "license": "MIT",
             "bin": {
                 "esbuild": "bin/esbuild"
             },
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             },
             "optionalDependencies": {
-                "@esbuild/android-arm": "0.18.12",
-                "@esbuild/android-arm64": "0.18.12",
-                "@esbuild/android-x64": "0.18.12",
-                "@esbuild/darwin-arm64": "0.18.12",
-                "@esbuild/darwin-x64": "0.18.12",
-                "@esbuild/freebsd-arm64": "0.18.12",
-                "@esbuild/freebsd-x64": "0.18.12",
-                "@esbuild/linux-arm": "0.18.12",
-                "@esbuild/linux-arm64": "0.18.12",
-                "@esbuild/linux-ia32": "0.18.12",
-                "@esbuild/linux-loong64": "0.18.12",
-                "@esbuild/linux-mips64el": "0.18.12",
-                "@esbuild/linux-ppc64": "0.18.12",
-                "@esbuild/linux-riscv64": "0.18.12",
-                "@esbuild/linux-s390x": "0.18.12",
-                "@esbuild/linux-x64": "0.18.12",
-                "@esbuild/netbsd-x64": "0.18.12",
-                "@esbuild/openbsd-x64": "0.18.12",
-                "@esbuild/sunos-x64": "0.18.12",
-                "@esbuild/win32-arm64": "0.18.12",
-                "@esbuild/win32-ia32": "0.18.12",
-                "@esbuild/win32-x64": "0.18.12"
+                "@esbuild/aix-ppc64": "0.25.0",
+                "@esbuild/android-arm": "0.25.0",
+                "@esbuild/android-arm64": "0.25.0",
+                "@esbuild/android-x64": "0.25.0",
+                "@esbuild/darwin-arm64": "0.25.0",
+                "@esbuild/darwin-x64": "0.25.0",
+                "@esbuild/freebsd-arm64": "0.25.0",
+                "@esbuild/freebsd-x64": "0.25.0",
+                "@esbuild/linux-arm": "0.25.0",
+                "@esbuild/linux-arm64": "0.25.0",
+                "@esbuild/linux-ia32": "0.25.0",
+                "@esbuild/linux-loong64": "0.25.0",
+                "@esbuild/linux-mips64el": "0.25.0",
+                "@esbuild/linux-ppc64": "0.25.0",
+                "@esbuild/linux-riscv64": "0.25.0",
+                "@esbuild/linux-s390x": "0.25.0",
+                "@esbuild/linux-x64": "0.25.0",
+                "@esbuild/netbsd-arm64": "0.25.0",
+                "@esbuild/netbsd-x64": "0.25.0",
+                "@esbuild/openbsd-arm64": "0.25.0",
+                "@esbuild/openbsd-x64": "0.25.0",
+                "@esbuild/sunos-x64": "0.25.0",
+                "@esbuild/win32-arm64": "0.25.0",
+                "@esbuild/win32-ia32": "0.25.0",
+                "@esbuild/win32-x64": "0.25.0"
             }
         },
         "node_modules/escalade": {
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 0a603767705..3f09033051b 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -59,7 +59,7 @@
         "@typescript-eslint/parser": "^6.0.0",
         "@vscode/test-electron": "^2.3.8",
         "@vscode/vsce": "^3.0.0",
-        "esbuild": "^0.18.12",
+        "esbuild": "^0.25.0",
         "eslint": "^8.44.0",
         "eslint-config-prettier": "^8.8.0",
         "ovsx": "^0.8.2",
@@ -1473,8 +1473,8 @@
             {
                 "title": "files",
                 "properties": {
-                    "rust-analyzer.files.excludeDirs": {
-                        "markdownDescription": "These directories will be ignored by rust-analyzer. They are\nrelative to the workspace root, and globs are not supported. You may\nalso need to add the folders to Code's `files.watcherExclude`.",
+                    "rust-analyzer.files.exclude": {
+                        "markdownDescription": "These paths (file/directories) will be ignored by rust-analyzer. They are\nrelative to the workspace root, and globs are not supported. You may\nalso need to add the folders to Code's `files.watcherExclude`.",
                         "default": [],
                         "type": "array",
                         "items": {
diff --git a/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md b/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md
index fda4ac80023..aabe0dd662b 100644
--- a/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md
+++ b/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md
@@ -5,6 +5,7 @@ Add the following to settings.json to mark Rust library sources as read-only:
 ```json
 "files.readonlyInclude": {
   "**/.cargo/registry/src/**/*.rs": true,
+  "**/.cargo/git/checkouts/**/*.rs": true,
   "**/lib/rustlib/src/rust/library/**/*.rs": true,
 },
 ```
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index f414893b6cd..4006d06e4fe 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-d9a4a47b8b3dc0bdff83360cea2013200d60d49c
+273465e1f2932a30a5b56ac95859cdc86f3f33fa
diff --git a/src/tools/rust-analyzer/xtask/src/codegen.rs b/src/tools/rust-analyzer/xtask/src/codegen.rs
index 18f49643dc7..e84c259e979 100644
--- a/src/tools/rust-analyzer/xtask/src/codegen.rs
+++ b/src/tools/rust-analyzer/xtask/src/codegen.rs
@@ -117,7 +117,7 @@ impl fmt::Display for Location {
         let path = self.file.strip_prefix(project_root()).unwrap().display().to_string();
         let path = path.replace('\\', "/");
         let name = self.file.file_name().unwrap();
-        write!(f, " [{}]({}#{}) ", name.to_str().unwrap(), path, self.line)
+        write!(f, " [{}](/{}#{}) ", name.to_str().unwrap(), path, self.line)
     }
 }
 
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index b31bf61a6fb..ddcf315a267 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -447,6 +447,13 @@ dependencies = [
 ]
 
 [[package]]
+name = "error_index_generator"
+version = "0.0.0"
+dependencies = [
+ "mdbook",
+]
+
+[[package]]
 name = "fastrand"
 version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -867,9 +874,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.44"
+version = "0.4.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9da1e54401fe5d45a664c57e112e70f18e8c5a73e268c179305b932ee864574"
+checksum = "b07d36d96ffe1b5b16ddf2bc80b3b26bb7a498b2a6591061250bf0af8e8095ad"
 dependencies = [
  "ammonia",
  "anyhow",
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index 9f9846cdee0..6aec0bec0fa 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -1,4 +1,5 @@
 [workspace]
+members = ["../error_index_generator"]
 
 [package]
 name = "rustbook"
@@ -14,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3"
 mdbook-spec = { path = "../../doc/reference/mdbook-spec" }
 
 [dependencies.mdbook]
-version = "0.4.44"
+version = "0.4.45"
 default-features = false
 features = ["search"]
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index e8e7dfe0d84..51e58b4e4fc 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -99,7 +99,6 @@ const EXCEPTIONS: ExceptionList = &[
     ("dissimilar", "Apache-2.0"),                            // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps)
     ("fluent-langneg", "Apache-2.0"),                        // rustc (fluent translations)
     ("foldhash", "Zlib"),                                    // rustc
-    ("mdbook", "MPL-2.0"),                                   // mdbook
     ("option-ext", "MPL-2.0"),                               // cargo-miri (via `directories`)
     ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"),     // rustc (license is the same as LLVM uses)
     ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0                       // cargo/... (because of serde)
@@ -667,7 +666,7 @@ pub static CRATES: &[&str] = &[
         for extra in expected.difference(&proc_macro_deps) {
             tidy_error!(
                 bad,
-                "`{extra}` is not registered in `src/bootstrap/src/utils/proc_macro_deps.rs`, but is not a proc-macro crate dependency",
+                "`{extra}` is registered in `src/bootstrap/src/utils/proc_macro_deps.rs`, but is not a proc-macro crate dependency",
             );
         }
         if *bad != old_bad {
diff --git a/tests/assembly/asm/aarch64-types.rs b/tests/assembly/asm/aarch64-types.rs
index 439385b14b0..8e4e0850325 100644
--- a/tests/assembly/asm/aarch64-types.rs
+++ b/tests/assembly/asm/aarch64-types.rs
@@ -11,8 +11,6 @@
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
-// FIXME(f16_f128): Only needed for FIXME in check! and check_reg!
-#![feature(auto_traits, lang_items)]
 
 extern crate minicore;
 use minicore::*;
@@ -63,12 +61,6 @@ impl Copy for f16x8 {}
 impl Copy for f32x4 {}
 impl Copy for f64x2 {}
 
-// FIXME(f16_f128): Only needed for FIXME in check! and check_reg!
-#[lang = "freeze"]
-unsafe auto trait Freeze {}
-#[lang = "unpin"]
-auto trait Unpin {}
-
 extern "C" {
     fn extern_func();
     static extern_static: u8;
diff --git a/tests/assembly/closure-inherit-target-feature.rs b/tests/assembly/closure-inherit-target-feature.rs
index b629d8769ed..069204bbd34 100644
--- a/tests/assembly/closure-inherit-target-feature.rs
+++ b/tests/assembly/closure-inherit-target-feature.rs
@@ -8,8 +8,9 @@
 
 use std::arch::x86_64::{__m128, _mm_blend_ps};
 
+// Use an explicit return pointer to prevent tail call optimization.
 #[no_mangle]
-pub unsafe fn sse41_blend_nofeature(x: __m128, y: __m128) -> __m128 {
+pub unsafe fn sse41_blend_nofeature(x: __m128, y: __m128, ret: *mut __m128) {
     let f = {
         // check that _mm_blend_ps is not being inlined into the closure
         // CHECK-LABEL: {{sse41_blend_nofeature.*closure.*:}}
@@ -18,9 +19,9 @@ pub unsafe fn sse41_blend_nofeature(x: __m128, y: __m128) -> __m128 {
         // CHECK-NOT: blendps
         // CHECK: ret
         #[inline(never)]
-        |x, y| _mm_blend_ps(x, y, 0b0101)
+        |x, y, ret: *mut __m128| unsafe { *ret = _mm_blend_ps(x, y, 0b0101) }
     };
-    f(x, y)
+    f(x, y, ret);
 }
 
 #[no_mangle]
diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs
index ad760627b3a..2c39c830684 100644
--- a/tests/assembly/x86-return-float.rs
+++ b/tests/assembly/x86-return-float.rs
@@ -33,19 +33,18 @@ use minicore::*;
 // CHECK-LABEL: return_f32:
 #[no_mangle]
 pub fn return_f32(x: f32) -> f32 {
-    // CHECK: movl {{.*}}(%ebp), %eax
-    // CHECK-NOT: ax
-    // CHECK: retl
+    // CHECK: movss {{.*}}(%ebp), %xmm0
+    // CHECK-NEXT: popl %ebp
+    // CHECK-NEXT: retl
     x
 }
 
 // CHECK-LABEL: return_f64:
 #[no_mangle]
 pub fn return_f64(x: f64) -> f64 {
-    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
-    // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL:.*]]
-    // CHECK-NEXT: movsd %[[VAL]], (%[[PTR]])
-    // CHECK: retl
+    // CHECK: movsd {{.*}}(%ebp), %xmm0
+    // CHECK-NEXT: popl %ebp
+    // CHECK-NEXT: retl
     x
 }
 
@@ -157,7 +156,7 @@ pub unsafe fn call_f32(x: &mut f32) {
     }
     // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
     // CHECK: calll {{()|_}}get_f32
-    // CHECK-NEXT: movl %eax, (%[[PTR]])
+    // CHECK-NEXT: movss %xmm0, (%[[PTR]])
     *x = get_f32();
 }
 
@@ -169,8 +168,7 @@ pub unsafe fn call_f64(x: &mut f64) {
     }
     // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
     // CHECK: calll {{()|_}}get_f64
-    // CHECK: movsd {{.*}}(%{{ebp|esp}}), %[[VAL:.*]]
-    // CHECK-NEXT: movsd %[[VAL:.*]], (%[[PTR]])
+    // CHECK-NEXT: movlps %xmm0, (%[[PTR]])
     *x = get_f64();
 }
 
@@ -315,25 +313,21 @@ pub unsafe fn call_other_f64(x: &mut (usize, f64)) {
 #[no_mangle]
 pub fn return_f16(x: f16) -> f16 {
     // CHECK: pushl %ebp
-    // CHECK: movl %esp, %ebp
-    // CHECK: movzwl 8(%ebp), %eax
-    // CHECK: popl %ebp
-    // CHECK: retl
+    // CHECK-NEXT: movl %esp, %ebp
+    // CHECK-NEXT: pinsrw $0, 8(%ebp), %xmm0
+    // CHECK-NEXT: popl %ebp
+    // CHECK-NEXT: retl
     x
 }
 
 // CHECK-LABEL: return_f128:
 #[no_mangle]
 pub fn return_f128(x: f128) -> f128 {
-    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
-    // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
-    // CHECK-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
-    // CHECK-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL3:.*]]
-    // CHECK-NEXT: movl [[#%d,OFFSET+16]](%ebp), %[[VAL4:.*]]
-    // CHECK-NEXT: movl %[[VAL4:.*]] 12(%[[PTR]])
-    // CHECK-NEXT: movl %[[VAL3:.*]] 8(%[[PTR]])
-    // CHECK-NEXT: movl %[[VAL2:.*]] 4(%[[PTR]])
-    // CHECK-NEXT: movl %[[VAL1:.*]] (%[[PTR]])
-    // CHECK: retl
+    // CHECK: pushl %ebp
+    // CHECK-NEXT: movl %esp, %ebp
+    // linux-NEXT: movaps 8(%ebp), %xmm0
+    // win-NEXT: movups 8(%ebp), %xmm0
+    // CHECK-NEXT: popl %ebp
+    // CHECK-NEXT: retl
     x
 }
diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs
index 1c5f9eeba3c..0aa8b6b8f89 100644
--- a/tests/auxiliary/minicore.rs
+++ b/tests/auxiliary/minicore.rs
@@ -14,9 +14,20 @@
 //! <https://github.com/rust-lang/rust/blob/c0b5cc9003f6464c11ae1c0662c6a7e06f6f5cab/compiler/rustc_codegen_cranelift/example/mini_core.rs>.
 // ignore-tidy-linelength
 
-#![feature(no_core, lang_items, rustc_attrs, decl_macro, naked_functions, f16, f128)]
+#![feature(
+    no_core,
+    lang_items,
+    auto_traits,
+    freeze_impls,
+    negative_impls,
+    rustc_attrs,
+    decl_macro,
+    naked_functions,
+    f16,
+    f128,
+    asm_experimental_arch
+)]
 #![allow(unused, improper_ctypes_definitions, internal_features)]
-#![feature(asm_experimental_arch)]
 #![no_std]
 #![no_core]
 
@@ -42,6 +53,12 @@ pub trait Copy: Sized {}
 #[lang = "bikeshed_guaranteed_no_drop"]
 pub trait BikeshedGuaranteedNoDrop {}
 
+#[lang = "freeze"]
+pub unsafe auto trait Freeze {}
+
+#[lang = "unpin"]
+pub auto trait Unpin {}
+
 impl_marker_trait!(
     Copy => [
         bool, char,
@@ -83,6 +100,7 @@ impl<T: Copy + ?Sized> Copy for ManuallyDrop<T> {}
 pub struct UnsafeCell<T: ?Sized> {
     value: T,
 }
+impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
 
 #[rustc_builtin_macro]
 pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) {
diff --git a/tests/codegen/abi-win64-zst.rs b/tests/codegen/abi-win64-zst.rs
index dd361898144..825a5c1b09c 100644
--- a/tests/codegen/abi-win64-zst.rs
+++ b/tests/codegen/abi-win64-zst.rs
@@ -1,4 +1,5 @@
 //@ compile-flags: -Z merge-functions=disabled
+//@ add-core-stubs
 
 //@ revisions: windows-gnu
 //@[windows-gnu] compile-flags: --target x86_64-pc-windows-gnu
@@ -13,12 +14,12 @@
 //@[linux] compile-flags: --target x86_64-unknown-linux-gnu
 //@[linux] needs-llvm-components: x86
 
-#![feature(no_core, lang_items, rustc_attrs, abi_vectorcall)]
+#![feature(no_core, rustc_attrs, abi_vectorcall)]
 #![no_core]
 #![crate_type = "lib"]
 
-#[lang = "sized"]
-trait Sized {}
+extern crate minicore;
+use minicore::*;
 
 // Make sure the argument is always passed when explicitly requesting a Windows ABI.
 // Our goal here is to match clang: <https://clang.godbolt.org/z/Wr4jMWq3P>.
diff --git a/tests/codegen/abi-x86-sse.rs b/tests/codegen/abi-x86-sse.rs
new file mode 100644
index 00000000000..837bf6134b0
--- /dev/null
+++ b/tests/codegen/abi-x86-sse.rs
@@ -0,0 +1,36 @@
+//@ compile-flags: -Z merge-functions=disabled
+
+//@ revisions: x86-64
+//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86-64] needs-llvm-components: x86
+
+//@ revisions: x86-32
+//@[x86-32] compile-flags: --target i686-unknown-linux-gnu
+//@[x86-32] needs-llvm-components: x86
+
+//@ revisions: x86-32-nosse
+//@[x86-32-nosse] compile-flags: --target i586-unknown-linux-gnu
+//@[x86-32-nosse] needs-llvm-components: x86
+
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![no_core]
+#![crate_type = "lib"]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+// Ensure this type is passed without ptr indirection on targets that
+// require SSE2.
+#[repr(simd)]
+pub struct Sse([f32; 4]);
+
+// x86-64: <4 x float> @sse_id(<4 x float> {{[^,]*}})
+// x86-32: <4 x float> @sse_id(<4 x float> {{[^,]*}})
+// x86-32-nosse: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}})
+#[no_mangle]
+pub fn sse_id(x: Sse) -> Sse {
+    x
+}
diff --git a/tests/codegen/align-byval-alignment-mismatch.rs b/tests/codegen/align-byval-alignment-mismatch.rs
index 835cc7393e5..46cfb2972df 100644
--- a/tests/codegen/align-byval-alignment-mismatch.rs
+++ b/tests/codegen/align-byval-alignment-mismatch.rs
@@ -1,4 +1,5 @@
 // ignore-tidy-linelength
+//@ add-core-stubs
 //@ revisions:i686-linux x86_64-linux
 
 //@[i686-linux] compile-flags: --target i686-unknown-linux-gnu -C panic=abort
@@ -16,18 +17,14 @@
 // on i686-unknown-linux-gnu, since the alignment needs to be increased, and should codegen
 // to a direct call on x86_64-unknown-linux-gnu, where byval alignment matches Rust alignment.
 
-#![feature(no_core, lang_items)]
+#![feature(no_core)]
 #![crate_type = "lib"]
 #![no_std]
 #![no_core]
 #![allow(non_camel_case_types)]
 
-#[lang = "sized"]
-trait Sized {}
-#[lang = "freeze"]
-trait Freeze {}
-#[lang = "copy"]
-trait Copy {}
+extern crate minicore;
+use minicore::*;
 
 // This type has align 1 in Rust, but as a byval argument on i686-linux, it will have align 4.
 #[repr(C)]
diff --git a/tests/codegen/align-byval-vector.rs b/tests/codegen/align-byval-vector.rs
index 60d49f93081..c33b41a7bbe 100644
--- a/tests/codegen/align-byval-vector.rs
+++ b/tests/codegen/align-byval-vector.rs
@@ -1,3 +1,4 @@
+//@ add-core-stubs
 //@ revisions:x86-linux x86-darwin
 
 //@[x86-linux] compile-flags: --target i686-unknown-linux-gnu
@@ -7,18 +8,14 @@
 
 // Tests that aggregates containing vector types get their alignment increased to 16 on Darwin.
 
-#![feature(no_core, lang_items, repr_simd, simd_ffi)]
+#![feature(no_core, repr_simd, simd_ffi)]
 #![crate_type = "lib"]
 #![no_std]
 #![no_core]
 #![allow(non_camel_case_types)]
 
-#[lang = "sized"]
-trait Sized {}
-#[lang = "freeze"]
-trait Freeze {}
-#[lang = "copy"]
-trait Copy {}
+extern crate minicore;
+use minicore::*;
 
 #[repr(simd)]
 pub struct i32x4([i32; 4]);
diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs
index b057147ab13..75dabd74a79 100644
--- a/tests/codegen/align-byval.rs
+++ b/tests/codegen/align-byval.rs
@@ -1,4 +1,5 @@
 // ignore-tidy-linelength
+//@ add-core-stubs
 //@ revisions:m68k x86_64-linux x86_64-windows i686-linux i686-windows
 
 //@[m68k] compile-flags: --target m68k-unknown-linux-gnu
@@ -16,20 +17,13 @@
 // The only targets that use `byval` are m68k, x86-64, and x86.
 // Note also that Windows mandates a by-ref ABI here, so it does not use byval.
 
-#![feature(no_core, lang_items)]
+#![feature(no_core)]
 #![crate_type = "lib"]
 #![no_std]
 #![no_core]
 
-#[lang = "sized"]
-trait Sized {}
-#[lang = "freeze"]
-trait Freeze {}
-#[lang = "copy"]
-trait Copy {}
-
-impl Copy for i32 {}
-impl Copy for i64 {}
+extern crate minicore;
+use minicore::*;
 
 // This struct can be represented as a pair, so it exercises the OperandValue::Pair
 // codepath in `codegen_argument`.
diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs
index 562a8e6c9e9..d87bab1172a 100644
--- a/tests/codegen/float/f128.rs
+++ b/tests/codegen/float/f128.rs
@@ -1,8 +1,11 @@
 // 32-bit x86 returns float types differently to avoid the x87 stack.
 // 32-bit systems will return 128bit values using a return area pointer.
 // Emscripten aligns f128 to 8 bytes, not 16.
-//@ revisions: x86 bit32 bit64 emscripten
-//@[x86] only-x86
+//@ revisions: x86-sse x86-nosse bit32 bit64 emscripten
+//@[x86-sse] only-x86
+//@[x86-sse] only-rustc_abi-x86-sse2
+//@[x86-nosse] only-x86
+//@[x86-nosse] ignore-rustc_abi-x86-sse2
 //@[bit32] ignore-x86
 //@[bit32] ignore-emscripten
 //@[bit32] only-32bit
@@ -60,7 +63,8 @@ pub fn f128_le(a: f128, b: f128) -> bool {
     a <= b
 }
 
-// x86-LABEL: void @f128_neg({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f128_neg({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_neg(fp128
 // bit32-LABEL: void @f128_neg({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_neg(
 // emscripten-LABEL: void @f128_neg({{.*}}sret([16 x i8])
@@ -70,7 +74,8 @@ pub fn f128_neg(a: f128) -> f128 {
     -a
 }
 
-// x86-LABEL: void @f128_add({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f128_add({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_add(fp128
 // bit32-LABEL: void @f128_add({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_add(
 // emscripten-LABEL: void @f128_add({{.*}}sret([16 x i8])
@@ -80,7 +85,8 @@ pub fn f128_add(a: f128, b: f128) -> f128 {
     a + b
 }
 
-// x86-LABEL: void @f128_sub({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f128_sub({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_sub(fp128
 // bit32-LABEL: void @f128_sub({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_sub(
 // emscripten-LABEL: void @f128_sub({{.*}}sret([16 x i8])
@@ -90,7 +96,8 @@ pub fn f128_sub(a: f128, b: f128) -> f128 {
     a - b
 }
 
-// x86-LABEL: void @f128_mul({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f128_mul({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_mul(fp128
 // bit32-LABEL: void @f128_mul({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_mul(
 // emscripten-LABEL: void @f128_mul({{.*}}sret([16 x i8])
@@ -100,7 +107,8 @@ pub fn f128_mul(a: f128, b: f128) -> f128 {
     a * b
 }
 
-// x86-LABEL: void @f128_div({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f128_div({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_div(fp128
 // bit32-LABEL: void @f128_div({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_div(
 // emscripten-LABEL: void @f128_div({{.*}}sret([16 x i8])
@@ -110,7 +118,8 @@ pub fn f128_div(a: f128, b: f128) -> f128 {
     a / b
 }
 
-// x86-LABEL: void @f128_rem({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f128_rem({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_rem(fp128
 // bit32-LABEL: void @f128_rem({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_rem(
 // emscripten-LABEL: void @f128_rem({{.*}}sret([16 x i8])
@@ -162,7 +171,8 @@ pub fn f128_rem_assign(a: &mut f128, b: f128) {
 
 /* float to float conversions */
 
-// x86-LABEL: i16 @f128_as_f16(
+// x86-sse-LABEL: <2 x i8> @f128_as_f16(
+// x86-nosse-LABEL: i16 @f128_as_f16(
 // bits32-LABEL: half @f128_as_f16(
 // bits64-LABEL: half @f128_as_f16(
 #[no_mangle]
@@ -171,7 +181,8 @@ pub fn f128_as_f16(a: f128) -> f16 {
     a as f16
 }
 
-// x86-LABEL: i32 @f128_as_f32(
+// x86-sse-LABEL: <4 x i8> @f128_as_f32(
+// x86-nosse-LABEL: i32 @f128_as_f32(
 // bit32-LABEL: float @f128_as_f32(
 // bit64-LABEL: float @f128_as_f32(
 // emscripten-LABEL: float @f128_as_f32(
@@ -181,7 +192,8 @@ pub fn f128_as_f32(a: f128) -> f32 {
     a as f32
 }
 
-// x86-LABEL: void @f128_as_f64(
+// x86-sse-LABEL: <8 x i8> @f128_as_f64(
+// x86-nosse-LABEL: void @f128_as_f64({{.*}}sret([8 x i8])
 // bit32-LABEL: double @f128_as_f64(
 // bit64-LABEL: double @f128_as_f64(
 // emscripten-LABEL: double @f128_as_f64(
@@ -191,7 +203,8 @@ pub fn f128_as_f64(a: f128) -> f64 {
     a as f64
 }
 
-// x86-LABEL: void @f128_as_self({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_as_self(
+// x86-nosse-LABEL: void @f128_as_self({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_as_self({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_as_self(
 // emscripten-LABEL: void @f128_as_self({{.*}}sret([16 x i8])
@@ -204,7 +217,8 @@ pub fn f128_as_self(a: f128) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f16_as_f128(
+// x86-nosse-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f16_as_f128(
 // emscripten-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
@@ -214,7 +228,8 @@ pub fn f16_as_f128(a: f16) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @f32_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f32_as_f128(
+// x86-nosse-LABEL: void @f32_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f32_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f32_as_f128(
 // emscripten-LABEL: void @f32_as_f128({{.*}}sret([16 x i8])
@@ -224,7 +239,8 @@ pub fn f32_as_f128(a: f32) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @f64_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f64_as_f128(
+// x86-nosse-LABEL: void @f64_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f64_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f64_as_f128(
 // emscripten-LABEL: void @f64_as_f128({{.*}}sret([16 x i8])
@@ -263,7 +279,8 @@ pub fn f128_as_u64(a: f128) -> u64 {
     a as u64
 }
 
-// x86-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
 // bit64-LABEL: i128 @f128_as_u128(
 // emscripten-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
@@ -300,7 +317,8 @@ pub fn f128_as_i64(a: f128) -> i64 {
     a as i64
 }
 
-// x86-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
 // bit64-LABEL: i128 @f128_as_i128(
 // emscripten-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
@@ -312,7 +330,8 @@ pub fn f128_as_i128(a: f128) -> i128 {
 
 /* int to float conversions */
 
-// x86-LABEL: void @u8_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @u8_as_f128(
+// x86-nosse-LABEL: void @u8_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @u8_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @u8_as_f128(
 // emscripten-LABEL: void @u8_as_f128({{.*}}sret([16 x i8])
@@ -322,7 +341,8 @@ pub fn u8_as_f128(a: u8) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @u16_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @u16_as_f128(
+// x86-nosse-LABEL: void @u16_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @u16_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @u16_as_f128(
 // emscripten-LABEL: void @u16_as_f128({{.*}}sret([16 x i8])
@@ -332,7 +352,8 @@ pub fn u16_as_f128(a: u16) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @u32_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @u32_as_f128(
+// x86-nosse-LABEL: void @u32_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @u32_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @u32_as_f128(
 // emscripten-LABEL: void @u32_as_f128({{.*}}sret([16 x i8])
@@ -342,7 +363,8 @@ pub fn u32_as_f128(a: u32) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @u64_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @u64_as_f128(
+// x86-nosse-LABEL: void @u64_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @u64_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @u64_as_f128(
 // emscripten-LABEL: void @u64_as_f128({{.*}}sret([16 x i8])
@@ -352,7 +374,8 @@ pub fn u64_as_f128(a: u64) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @u128_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @u128_as_f128(
+// x86-nosse-LABEL: void @u128_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @u128_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @u128_as_f128(
 // emscripten-LABEL: void @u128_as_f128({{.*}}sret([16 x i8])
@@ -362,7 +385,8 @@ pub fn u128_as_f128(a: u128) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @i8_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @i8_as_f128(
+// x86-nosse-LABEL: void @i8_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @i8_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @i8_as_f128(
 // emscripten-LABEL: void @i8_as_f128({{.*}}sret([16 x i8])
@@ -372,7 +396,8 @@ pub fn i8_as_f128(a: i8) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @i16_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @i16_as_f128(
+// x86-nosse-LABEL: void @i16_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @i16_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @i16_as_f128(
 // emscripten-LABEL: void @i16_as_f128({{.*}}sret([16 x i8])
@@ -382,7 +407,8 @@ pub fn i16_as_f128(a: i16) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @i32_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @i32_as_f128(
+// x86-nosse-LABEL: void @i32_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @i32_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @i32_as_f128(
 // emscripten-LABEL: void @i32_as_f128({{.*}}sret([16 x i8])
@@ -392,7 +418,8 @@ pub fn i32_as_f128(a: i32) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @i64_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @i64_as_f128(
+// x86-nosse-LABEL: void @i64_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @i64_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @i64_as_f128(
 // emscripten-LABEL: void @i64_as_f128({{.*}}sret([16 x i8])
@@ -402,7 +429,8 @@ pub fn i64_as_f128(a: i64) -> f128 {
     a as f128
 }
 
-// x86-LABEL: void @i128_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @i128_as_f128(
+// x86-nosse-LABEL: void @i128_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @i128_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @i128_as_f128(
 // emscripten-LABEL: void @i128_as_f128({{.*}}sret([16 x i8])
diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs
index 5c3a5893b9d..0c40606ad8a 100644
--- a/tests/codegen/float/f16.rs
+++ b/tests/codegen/float/f16.rs
@@ -1,7 +1,10 @@
 // 32-bit x86 returns float types differently to avoid the x87 stack.
 // 32-bit systems will return 128bit values using a return area pointer.
-//@ revisions: x86 bit32 bit64
-//@[x86] only-x86
+//@ revisions: x86-sse x86-nosse bit32 bit64
+//@[x86-sse] only-x86
+//@[x86-sse] only-rustc_abi-x86-sse2
+//@[x86-nosse] only-x86
+//@[x86-nosse] ignore-rustc_abi-x86-sse2
 //@[bit32] ignore-x86
 //@[bit32] only-32bit
 //@[bit64] ignore-x86
@@ -59,8 +62,10 @@ pub fn f16_le(a: f16, b: f16) -> bool {
 }
 
 // This is where we check the argument and return ABI for f16.
-// other-LABEL: half @f16_neg(half
-// x86-LABEL: i16 @f16_neg(half
+// bit32-LABEL: half @f16_neg(half
+// bit64-LABEL: half @f16_neg(half
+// x86-sse-LABEL: <2 x i8> @f16_neg(half
+// x86-nosse-LABEL: i16 @f16_neg(half
 #[no_mangle]
 pub fn f16_neg(a: f16) -> f16 {
     // CHECK: fneg half %{{.+}}
@@ -144,17 +149,23 @@ pub fn f16_rem_assign(a: &mut f16, b: f16) {
 
 /* float to float conversions */
 
-// other-LABEL: half @f16_as_self(
-// x86-LABEL: i16 @f16_as_self(
+// bit32-LABEL: half @f16_as_self(
+// bit64-LABEL: half @f16_as_self(
+// x86-sse-LABEL: <2 x i8> @f16_as_self(
+// x86-nosse-LABEL: i16 @f16_as_self(
 #[no_mangle]
 pub fn f16_as_self(a: f16) -> f16 {
-    // other-CHECK: ret half %{{.+}}
-    // x86-CHECK: bitcast half
-    // x86-CHECK: ret i16
+    // bit32-CHECK: ret half %{{.+}}
+    // bit64-CHECK: ret half %{{.+}}
+    // x86-sse-CHECK: bitcast half
+    // x86-nosse-CHECK: bitcast half
+    // x86-sse-CHECK: ret i16
+    // x86-nosse-CHECK: ret i16
     a as f16
 }
 
-// x86-LABEL: i32 @f16_as_f32(
+// x86-sse-LABEL: <4 x i8> @f16_as_f32(
+// x86-nosse-LABEL: i32 @f16_as_f32(
 // bit32-LABEL: float @f16_as_f32(
 // bit64-LABEL: float @f16_as_f32(
 #[no_mangle]
@@ -163,7 +174,8 @@ pub fn f16_as_f32(a: f16) -> f32 {
     a as f32
 }
 
-// x86-LABEL: void @f16_as_f64(
+// x86-sse-LABEL: <8 x i8> @f16_as_f64(
+// x86-nosse-LABEL: void @f16_as_f64({{.*}}sret([8 x i8])
 // bit32-LABEL: double @f16_as_f64(
 // bit64-LABEL: double @f16_as_f64(
 #[no_mangle]
@@ -172,7 +184,8 @@ pub fn f16_as_f64(a: f16) -> f64 {
     a as f64
 }
 
-// x86-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f16_as_f128(
+// x86-nosse-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f16_as_f128(
 #[no_mangle]
@@ -231,7 +244,8 @@ pub fn f16_as_u64(a: f16) -> u64 {
     a as u64
 }
 
-// x86-LABEL: void @f16_as_u128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: void @f16_as_u128({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f16_as_u128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f16_as_u128({{.*}}sret([16 x i8])
 // bit64-LABEL: i128 @f16_as_u128(
 #[no_mangle]
@@ -267,7 +281,8 @@ pub fn f16_as_i64(a: f16) -> i64 {
     a as i64
 }
 
-// x86-LABEL: void @f16_as_i128({{.*}}sret([16 x i8])
+// x86-sse-LABEL: void @f16_as_i128({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f16_as_i128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f16_as_i128({{.*}}sret([16 x i8])
 // bit64-LABEL: i128 @f16_as_i128(
 #[no_mangle]
diff --git a/tests/codegen/intrinsics/transmute-x64.rs b/tests/codegen/intrinsics/transmute-x64.rs
index fe68f183667..be45e4db90f 100644
--- a/tests/codegen/intrinsics/transmute-x64.rs
+++ b/tests/codegen/intrinsics/transmute-x64.rs
@@ -6,15 +6,6 @@
 use std::arch::x86_64::{__m128, __m128i, __m256i};
 use std::mem::transmute;
 
-// CHECK-LABEL: @check_sse_float_to_int(
-#[no_mangle]
-pub unsafe fn check_sse_float_to_int(x: __m128) -> __m128i {
-    // CHECK-NOT: alloca
-    // CHECK: %0 = load <4 x float>, ptr %x, align 16
-    // CHECK: store <4 x float> %0, ptr %_0, align 16
-    transmute(x)
-}
-
 // CHECK-LABEL: @check_sse_pair_to_avx(
 #[no_mangle]
 pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i {
diff --git a/tests/codegen/issues/issue-32031.rs b/tests/codegen/issues/issue-32031.rs
index 4d6895166f1..559e8d947fb 100644
--- a/tests/codegen/issues/issue-32031.rs
+++ b/tests/codegen/issues/issue-32031.rs
@@ -1,7 +1,7 @@
 //@ compile-flags: -C no-prepopulate-passes -Copt-level=0
 // 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack.
 //@ revisions: x86 other
-//@[x86] only-x86
+//@[x86] only-rustc_abi-x86-sse2
 //@[other] ignore-x86
 
 #![crate_type = "lib"]
@@ -10,7 +10,7 @@
 pub struct F32(f32);
 
 // other: define{{.*}}float @add_newtype_f32(float %a, float %b)
-// x86: define{{.*}}i32 @add_newtype_f32(float %a, float %b)
+// x86: define{{.*}}<4 x i8> @add_newtype_f32(float %a, float %b)
 #[inline(never)]
 #[no_mangle]
 pub fn add_newtype_f32(a: F32, b: F32) -> F32 {
@@ -21,7 +21,7 @@ pub fn add_newtype_f32(a: F32, b: F32) -> F32 {
 pub struct F64(f64);
 
 // other: define{{.*}}double @add_newtype_f64(double %a, double %b)
-// x86: define{{.*}}void @add_newtype_f64(ptr{{.*}}sret([8 x i8]){{.*}}%_0, double %a, double %b)
+// x86: define{{.*}}<8 x i8> @add_newtype_f64(double %a, double %b)
 #[inline(never)]
 #[no_mangle]
 pub fn add_newtype_f64(a: F64, b: F64) -> F64 {
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
index 75f989d6e12..0d21d510557 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
@@ -1,5 +1,14 @@
 //
 //@ compile-flags: -C no-prepopulate-passes
+// LLVM IR isn't very portable and the one tested here depends on the ABI
+// which is different between x86 (where we use SSE registers) and others.
+// `x86-64` and `x86-32-sse2` are identical, but compiletest does not support
+// taking the union of multiple `only` annotations.
+//@ revisions: x86-64 x86-32-sse2 other
+//@[x86-64] only-x86_64
+//@[x86-32-sse2] only-rustc_abi-x86-sse2
+//@[other] ignore-rustc_abi-x86-sse2
+//@[other] ignore-x86_64
 
 #![crate_type = "lib"]
 #![allow(non_camel_case_types)]
@@ -38,7 +47,9 @@ pub fn build_array_s(x: [f32; 4]) -> S<4> {
 #[no_mangle]
 pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> {
     // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]]
-    // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]]
+    // x86-32: ret <4 x float> %[[VAL:.+]]
+    // x86-64: ret <4 x float> %[[VAL:.+]]
+    // other: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]]
     unsafe { std::mem::transmute(x) }
 }
 
@@ -53,6 +64,8 @@ pub fn build_array_t(x: [f32; 4]) -> T {
 #[no_mangle]
 pub fn build_array_transmute_t(x: [f32; 4]) -> T {
     // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]]
-    // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]]
+    // x86-32: ret <4 x float> %[[VAL:.+]]
+    // x86-64: ret <4 x float> %[[VAL:.+]]
+    // other: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]]
     unsafe { std::mem::transmute(x) }
 }
diff --git a/tests/codegen/simd/packed-simd.rs b/tests/codegen/simd/packed-simd.rs
index 1df09c96e6c..a27d5e3af45 100644
--- a/tests/codegen/simd/packed-simd.rs
+++ b/tests/codegen/simd/packed-simd.rs
@@ -1,4 +1,5 @@
 //@ revisions:opt3 noopt
+//@ only-x86_64
 //@[opt3] compile-flags: -Copt-level=3
 //@[noopt] compile-flags: -Cno-prepopulate-passes
 
@@ -14,14 +15,14 @@ use core::{mem, ptr};
 
 #[repr(simd, packed)]
 #[derive(Copy, Clone)]
-pub struct Simd<T, const N: usize>([T; N]);
+pub struct PackedSimd<T, const N: usize>([T; N]);
 
 #[repr(simd)]
 #[derive(Copy, Clone)]
 pub struct FullSimd<T, const N: usize>([T; N]);
 
 // non-powers-of-two have padding and need to be expanded to full vectors
-fn load<T, const N: usize>(v: Simd<T, N>) -> FullSimd<T, N> {
+fn load<T, const N: usize>(v: PackedSimd<T, N>) -> FullSimd<T, N> {
     unsafe {
         let mut tmp = mem::MaybeUninit::<FullSimd<T, N>>::uninit();
         ptr::copy_nonoverlapping(&v as *const _, tmp.as_mut_ptr().cast(), 1);
@@ -29,18 +30,16 @@ fn load<T, const N: usize>(v: Simd<T, N>) -> FullSimd<T, N> {
     }
 }
 
-// CHECK-LABEL: square_packed_full
-// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align (8|16)]]{{[^%]*}} [[RET_VREG:%[_0-9]*]]
-// CHECK-SAME: ptr{{[a-z_ ]*}} align 4
+// CHECK-LABEL: define <3 x float> @square_packed_full(ptr{{[a-z_ ]*}} align 4 {{[^,]*}})
 #[no_mangle]
-pub fn square_packed_full(x: Simd<f32, 3>) -> FullSimd<f32, 3> {
-    // CHECK-NEXT: start
-    // noopt: alloca [[RET_TYPE]], [[RET_ALIGN]]
-    // CHECK: load <3 x float>
+pub fn square_packed_full(x: PackedSimd<f32, 3>) -> FullSimd<f32, 3> {
+    // The unoptimized version of this is not very interesting to check
+    // since `load` does not get inlined.
+    // opt3-NEXT: start:
+    // opt3-NEXT: load <3 x float>
     let x = load(x);
-    // CHECK: [[VREG:%[a-z0-9_]+]] = fmul <3 x float>
-    // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]]
-    // CHECK-NEXT: ret void
+    // opt3-NEXT: [[VREG:%[a-z0-9_]+]] = fmul <3 x float>
+    // opt3-NEXT: ret <3 x float> [[VREG:%[a-z0-9_]+]]
     unsafe { intrinsics::simd_mul(x, x) }
 }
 
@@ -48,7 +47,7 @@ pub fn square_packed_full(x: Simd<f32, 3>) -> FullSimd<f32, 3> {
 // CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align 4]]{{[^%]*}} [[RET_VREG:%[_0-9]*]]
 // CHECK-SAME: ptr{{[a-z_ ]*}} align 4
 #[no_mangle]
-pub fn square_packed(x: Simd<f32, 3>) -> Simd<f32, 3> {
+pub fn square_packed(x: PackedSimd<f32, 3>) -> PackedSimd<f32, 3> {
     // CHECK-NEXT: start
     // CHECK-NEXT: load <3 x float>
     // noopt-NEXT: load <3 x float>
diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs
index 92d40d8ac14..16022fad8af 100644
--- a/tests/codegen/union-abi.rs
+++ b/tests/codegen/union-abi.rs
@@ -2,8 +2,11 @@
 //@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
 // 32-bit x86 returns `f32` differently to avoid the x87 stack.
 // 32-bit systems will return 128bit values using a return area pointer.
-//@ revisions: x86 bit32 bit64
-//@[x86] only-x86
+//@ revisions: x86-sse x86-nosse bit32 bit64
+//@[x86-sse] only-x86
+//@[x86-sse] only-rustc_abi-x86-sse2
+//@[x86-nosse] only-x86
+//@[x86-nosse] ignore-rustc_abi-x86-sse2
 //@[bit32] ignore-x86
 //@[bit32] only-32bit
 //@[bit64] ignore-x86
@@ -75,7 +78,8 @@ pub union UnionF32 {
     a: f32,
 }
 
-// x86: define {{(dso_local )?}}i32 @test_UnionF32(float %_1)
+// x86-sse: define {{(dso_local )?}}<4 x i8> @test_UnionF32(float %_1)
+// x86-nosse: define {{(dso_local )?}}i32 @test_UnionF32(float %_1)
 // bit32: define {{(dso_local )?}}float @test_UnionF32(float %_1)
 // bit64: define {{(dso_local )?}}float @test_UnionF32(float %_1)
 #[no_mangle]
@@ -88,7 +92,8 @@ pub union UnionF32F32 {
     b: f32,
 }
 
-// x86: define {{(dso_local )?}}i32 @test_UnionF32F32(float %_1)
+// x86-sse: define {{(dso_local )?}}<4 x i8> @test_UnionF32F32(float %_1)
+// x86-nosse: define {{(dso_local )?}}i32 @test_UnionF32F32(float %_1)
 // bit32: define {{(dso_local )?}}float @test_UnionF32F32(float %_1)
 // bit64: define {{(dso_local )?}}float @test_UnionF32F32(float %_1)
 #[no_mangle]
@@ -110,7 +115,8 @@ pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 {
 pub union UnionU128 {
     a: u128,
 }
-// x86: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1)
+// x86-sse: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1)
+// x86-nosse: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1)
 // bit32: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1)
 // bit64: define {{(dso_local )?}}i128 @test_UnionU128(i128 %_1)
 #[no_mangle]
diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff
index 727efe4b0d9..267a4c1cf6b 100644
--- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff
+++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff
@@ -47,6 +47,7 @@
 +         Deinit(_8);
 +         copy_nonoverlapping(dst = copy _9, src = copy _11, count = copy _7);
 +         StorageDead(_4);
++         nop;
           StorageDead(_2);
 -         _0 = move _1;
 +         StorageLive(_12);
@@ -61,6 +62,7 @@
 +         Deinit(_16);
 +         copy_nonoverlapping(dst = copy _17, src = copy _19, count = copy _15);
 +         StorageDead(_12);
++         nop;
           StorageDead(_1);
           return;
       }
diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff
index 8d0cd97f786..8e5c403cd7e 100644
--- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff
+++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff
@@ -47,6 +47,7 @@
 +         Deinit(_8);
 +         copy_nonoverlapping(dst = copy _9, src = copy _11, count = copy _7);
 +         StorageDead(_4);
++         nop;
           StorageDead(_2);
 -         _0 = move _1;
 +         StorageLive(_12);
@@ -61,6 +62,7 @@
 +         Deinit(_16);
 +         copy_nonoverlapping(dst = copy _17, src = copy _19, count = copy _15);
 +         StorageDead(_12);
++         nop;
           StorageDead(_1);
           return;
       }
diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff
index 6d1e2a72fdb..96c5aadd85f 100644
--- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff
+++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff
@@ -47,6 +47,7 @@
 +         Deinit(_8);
 +         copy_nonoverlapping(dst = copy _9, src = copy _11, count = copy _7);
 +         StorageDead(_4);
++         nop;
           StorageDead(_2);
 -         _0 = move _1;
 +         StorageLive(_12);
@@ -61,6 +62,7 @@
 +         Deinit(_16);
 +         copy_nonoverlapping(dst = copy _17, src = copy _19, count = copy _15);
 +         StorageDead(_12);
++         nop;
           StorageDead(_1);
           return;
       }
diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff
index 4b1406d0d62..d20e2e08eaa 100644
--- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff
+++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff
@@ -47,6 +47,7 @@
 +         Deinit(_8);
 +         copy_nonoverlapping(dst = copy _9, src = copy _11, count = copy _7);
 +         StorageDead(_4);
++         nop;
           StorageDead(_2);
 -         _0 = move _1;
 +         StorageLive(_12);
@@ -61,6 +62,7 @@
 +         Deinit(_16);
 +         copy_nonoverlapping(dst = copy _17, src = copy _19, count = copy _15);
 +         StorageDead(_12);
++         nop;
           StorageDead(_1);
           return;
       }
diff --git a/tests/run-make/rustc-crates-on-stable/rmake.rs b/tests/run-make/rustc-crates-on-stable/rmake.rs
index 9fbc675cc9a..cbc1f24b8c1 100644
--- a/tests/run-make/rustc-crates-on-stable/rmake.rs
+++ b/tests/run-make/rustc-crates-on-stable/rmake.rs
@@ -35,6 +35,8 @@ fn main() {
             "rustc_abi",
             "-p",
             "rustc_parse_format",
+            "-p",
+            "rustc_hashes",
         ])
         .run();
 }
diff --git a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout
index ca6e7750264..13e142df837 100644
--- a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout
+++ b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout
@@ -5,7 +5,7 @@ test $DIR/relative-path-include-bytes-132203.rs - (line 18) ... FAILED
 failures:
 
 ---- $DIR/relative-path-include-bytes-132203.rs - (line 18) stdout ----
-error: couldn't read `$DIR/relative-dir-empty-file`: No such file or directory (os error 2)
+error: couldn't read `$DIR/relative-dir-empty-file`: $FILE_NOT_FOUND_MSG (os error 2)
   --> $DIR/relative-path-include-bytes-132203.rs:19:9
    |
 LL | let x = include_bytes!("relative-dir-empty-file");
diff --git a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs
index 6fddaa49fac..ceacd69a5fd 100644
--- a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs
+++ b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs
@@ -1,4 +1,3 @@
-//@ ignore-windows different error message
 //@ revisions: edition2015 edition2024
 //@[edition2015]edition:2015
 //@[edition2015]check-fail
@@ -7,8 +6,9 @@
 //@[edition2024]edition:2024
 //@[edition2024]check-pass
 //@[edition2024]compile-flags:--test --test-args=--test-threads=1
-//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout: "tests.rustdoc-ui.doctest." -> "$$DIR/"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "`: .* \(os error 2\)" -> "`: $$FILE_NOT_FOUND_MSG (os error 2)"
 
 // https://github.com/rust-lang/rust/issues/132203
 // This version, because it's edition2024, passes thanks to the new
diff --git a/tests/ui-fulldeps/missing-rustc-driver-error.stderr b/tests/ui-fulldeps/missing-rustc-driver-error.stderr
index d7bf27d6349..faad6264522 100644
--- a/tests/ui-fulldeps/missing-rustc-driver-error.stderr
+++ b/tests/ui-fulldeps/missing-rustc-driver-error.stderr
@@ -2,5 +2,13 @@ error: crate `rustc_serialize` required to be available in rlib format, but was
    |
    = help: try adding `extern crate rustc_driver;` at the top level of this crate
 
+error: crate `rustc_hashes` required to be available in rlib format, but was not found in this form
+   |
+   = help: try adding `extern crate rustc_driver;` at the top level of this crate
+
+error: crate `rustc_stable_hash` required to be available in rlib format, but was not found in this form
+   |
+   = help: try adding `extern crate rustc_driver;` at the top level of this crate
+
 error: aborting due to NUMBER previous errors
 
diff --git a/tests/ui-fulldeps/obtain-borrowck.rs b/tests/ui-fulldeps/obtain-borrowck.rs
index c6bec4f77a0..84f6970c83a 100644
--- a/tests/ui-fulldeps/obtain-borrowck.rs
+++ b/tests/ui-fulldeps/obtain-borrowck.rs
@@ -67,7 +67,6 @@ impl rustc_driver::Callbacks for CompilerCalls {
     fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation {
         tcx.sess.dcx().abort_if_errors();
         // Collect definition ids of MIR bodies.
-        let hir = tcx.hir();
         let mut bodies = Vec::new();
 
         let crate_items = tcx.hir_crate_items(());
@@ -79,7 +78,7 @@ impl rustc_driver::Callbacks for CompilerCalls {
 
         for id in crate_items.trait_items() {
             if matches!(tcx.def_kind(id.owner_id), DefKind::AssocFn) {
-                let trait_item = hir.trait_item(id);
+                let trait_item = tcx.hir_trait_item(id);
                 if let rustc_hir::TraitItemKind::Fn(_, trait_fn) = &trait_item.kind {
                     if let rustc_hir::TraitFn::Provided(_) = trait_fn {
                         bodies.push(trait_item.owner_id);
diff --git a/tests/ui/abi/c-zst.aarch64-darwin.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr
index d9742612bcf..c8f7d0a517c 100644
--- a/tests/ui/abi/c-zst.aarch64-darwin.stderr
+++ b/tests/ui/abi/c-zst.aarch64-darwin.stderr
@@ -60,7 +60,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
            conv: C,
            can_unwind: false,
        }
-  --> $DIR/c-zst.rs:63:1
+  --> $DIR/c-zst.rs:64:1
    |
 LL | extern "C" fn pass_zst(_: ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr
index 0e98b5f806b..1015f7d8898 100644
--- a/tests/ui/abi/c-zst.powerpc-linux.stderr
+++ b/tests/ui/abi/c-zst.powerpc-linux.stderr
@@ -71,7 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
            conv: C,
            can_unwind: false,
        }
-  --> $DIR/c-zst.rs:63:1
+  --> $DIR/c-zst.rs:64:1
    |
 LL | extern "C" fn pass_zst(_: ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/c-zst.rs b/tests/ui/abi/c-zst.rs
index 6b299ffadb7..c1dac41f876 100644
--- a/tests/ui/abi/c-zst.rs
+++ b/tests/ui/abi/c-zst.rs
@@ -1,3 +1,4 @@
+//@ add-core-stubs
 //@ normalize-stderr: "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN"
 /*!
 C doesn't have zero-sized types... except it does.
@@ -52,12 +53,12 @@ extern "C" fn(i32, (), i32);
 //@[x86_64-pc-windows-gnu] needs-llvm-components: x86
 
 
-#![feature(lang_items, no_core, rustc_attrs)]
+#![feature(no_core, rustc_attrs)]
 #![no_core]
 #![crate_type = "lib"]
 
-#[lang = "sized"]
-trait Sized {}
+extern crate minicore;
+use minicore::*;
 
 #[rustc_abi(debug)]
 extern "C" fn pass_zst(_: ()) {} //~ ERROR: fn_abi
diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr
index 0e98b5f806b..1015f7d8898 100644
--- a/tests/ui/abi/c-zst.s390x-linux.stderr
+++ b/tests/ui/abi/c-zst.s390x-linux.stderr
@@ -71,7 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
            conv: C,
            can_unwind: false,
        }
-  --> $DIR/c-zst.rs:63:1
+  --> $DIR/c-zst.rs:64:1
    |
 LL | extern "C" fn pass_zst(_: ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr
index 0e98b5f806b..1015f7d8898 100644
--- a/tests/ui/abi/c-zst.sparc64-linux.stderr
+++ b/tests/ui/abi/c-zst.sparc64-linux.stderr
@@ -71,7 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
            conv: C,
            can_unwind: false,
        }
-  --> $DIR/c-zst.rs:63:1
+  --> $DIR/c-zst.rs:64:1
    |
 LL | extern "C" fn pass_zst(_: ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/c-zst.x86_64-linux.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr
index d9742612bcf..c8f7d0a517c 100644
--- a/tests/ui/abi/c-zst.x86_64-linux.stderr
+++ b/tests/ui/abi/c-zst.x86_64-linux.stderr
@@ -60,7 +60,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
            conv: C,
            can_unwind: false,
        }
-  --> $DIR/c-zst.rs:63:1
+  --> $DIR/c-zst.rs:64:1
    |
 LL | extern "C" fn pass_zst(_: ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
index 0e98b5f806b..1015f7d8898 100644
--- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
+++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
@@ -71,7 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
            conv: C,
            can_unwind: false,
        }
-  --> $DIR/c-zst.rs:63:1
+  --> $DIR/c-zst.rs:64:1
    |
 LL | extern "C" fn pass_zst(_: ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/associated-consts/issue-93835.rs b/tests/ui/associated-consts/issue-93835.rs
index 9cc33d53f9c..048681f0477 100644
--- a/tests/ui/associated-consts/issue-93835.rs
+++ b/tests/ui/associated-consts/issue-93835.rs
@@ -3,9 +3,11 @@
 fn e() {
     type_ascribe!(p, a<p:p<e=6>>);
     //~^ ERROR cannot find type `a` in this scope
+    //~| ERROR path separator must be a double colon
     //~| ERROR cannot find value
     //~| ERROR associated const equality
-    //~| ERROR cannot find trait `p` in this scope
+    //~| ERROR associated const equality
+    //~| ERROR failed to resolve: use of unresolved module or unlinked crate `p`
 }
 
 fn main() {}
diff --git a/tests/ui/associated-consts/issue-93835.stderr b/tests/ui/associated-consts/issue-93835.stderr
index dfe78b3d1f3..e154ae25de2 100644
--- a/tests/ui/associated-consts/issue-93835.stderr
+++ b/tests/ui/associated-consts/issue-93835.stderr
@@ -1,3 +1,15 @@
+error: path separator must be a double colon
+  --> $DIR/issue-93835.rs:4:25
+   |
+LL |     type_ascribe!(p, a<p:p<e=6>>);
+   |                         ^
+   |
+   = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+help: use a double colon instead
+   |
+LL |     type_ascribe!(p, a<p::p<e=6>>);
+   |                          +
+
 error[E0425]: cannot find value `p` in this scope
   --> $DIR/issue-93835.rs:4:19
    |
@@ -10,11 +22,15 @@ error[E0412]: cannot find type `a` in this scope
 LL |     type_ascribe!(p, a<p:p<e=6>>);
    |                      ^ not found in this scope
 
-error[E0405]: cannot find trait `p` in this scope
-  --> $DIR/issue-93835.rs:4:26
+error[E0658]: associated const equality is incomplete
+  --> $DIR/issue-93835.rs:4:28
    |
 LL |     type_ascribe!(p, a<p:p<e=6>>);
-   |                          ^ not found in this scope
+   |                            ^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` 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]: associated const equality is incomplete
   --> $DIR/issue-93835.rs:4:28
@@ -25,8 +41,17 @@ LL |     type_ascribe!(p, a<p:p<e=6>>);
    = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
    = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0433]: failed to resolve: use of unresolved module or unlinked crate `p`
+  --> $DIR/issue-93835.rs:4:24
+   |
+LL |     type_ascribe!(p, a<p:p<e=6>>);
+   |                        ^ use of unresolved module or unlinked crate `p`
+   |
+   = help: you might be missing a crate named `p`
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0405, E0412, E0425, E0658.
-For more information about an error, try `rustc --explain E0405`.
+Some errors have detailed explanations: E0412, E0425, E0433, E0658.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr
index 28e7975c7a2..305fbbd275f 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
-  --> $DIR/as_expression.rs:55:15
+  --> $DIR/as_expression.rs:56:15
    |
 LL |     SelectInt.check("bar");
    |               ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
index 4f685c508c7..90bb715a052 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
-  --> $DIR/as_expression.rs:55:21
+  --> $DIR/as_expression.rs:56:21
    |
 LL |     SelectInt.check("bar");
    |               ----- ^^^^^ the trait `AsExpression<<SelectInt as Expression>::SqlType>` is not implemented for `&str`
@@ -8,7 +8,7 @@ LL |     SelectInt.check("bar");
    |
    = help: the trait `AsExpression<Text>` is implemented for `&str`
 note: required by a bound in `Foo::check`
-  --> $DIR/as_expression.rs:46:12
+  --> $DIR/as_expression.rs:47:12
    |
 LL |     fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression
    |        ----- required by a bound in this associated function
@@ -17,7 +17,7 @@ LL |         T: AsExpression<Self::SqlType>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
 
 error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Text`
-  --> $DIR/as_expression.rs:55:5
+  --> $DIR/as_expression.rs:56:5
    |
 LL |     SelectInt.check("bar");
    |     ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
index 48c1ed2b02d..73a238ddf50 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
@@ -1,6 +1,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
+//@ reference: attributes.diagnostic.do_not_recommend.intro
 
 pub trait Expression {
     type SqlType;
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr
index 47597a5d405..8a478a5c733 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr
@@ -1,5 +1,5 @@
 warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
-  --> $DIR/does_not_acccept_args.rs:10:1
+  --> $DIR/does_not_acccept_args.rs:11:1
    |
 LL | #[diagnostic::do_not_recommend(not_accepted)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,13 +7,13 @@ LL | #[diagnostic::do_not_recommend(not_accepted)]
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
-  --> $DIR/does_not_acccept_args.rs:14:1
+  --> $DIR/does_not_acccept_args.rs:15:1
    |
 LL | #[diagnostic::do_not_recommend(not_accepted = "foo")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
-  --> $DIR/does_not_acccept_args.rs:18:1
+  --> $DIR/does_not_acccept_args.rs:19:1
    |
 LL | #[diagnostic::do_not_recommend(not_accepted(42))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr
index 47597a5d405..8a478a5c733 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr
@@ -1,5 +1,5 @@
 warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
-  --> $DIR/does_not_acccept_args.rs:10:1
+  --> $DIR/does_not_acccept_args.rs:11:1
    |
 LL | #[diagnostic::do_not_recommend(not_accepted)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,13 +7,13 @@ LL | #[diagnostic::do_not_recommend(not_accepted)]
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
-  --> $DIR/does_not_acccept_args.rs:14:1
+  --> $DIR/does_not_acccept_args.rs:15:1
    |
 LL | #[diagnostic::do_not_recommend(not_accepted = "foo")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
-  --> $DIR/does_not_acccept_args.rs:18:1
+  --> $DIR/does_not_acccept_args.rs:19:1
    |
 LL | #[diagnostic::do_not_recommend(not_accepted(42))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs
index eeff5e2e6e8..5c21c045e10 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs
@@ -2,6 +2,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
+//@ reference: attributes.diagnostic.do_not_recommend.syntax
 
 trait Foo {}
 trait Bar {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr
index ee6ebabadd9..e348f0c8902 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr
@@ -1,5 +1,5 @@
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:6:1
+  --> $DIR/incorrect-locations.rs:7:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,49 +7,49 @@ LL | #[diagnostic::do_not_recommend]
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:10:1
+  --> $DIR/incorrect-locations.rs:11:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:14:1
+  --> $DIR/incorrect-locations.rs:15:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:18:1
+  --> $DIR/incorrect-locations.rs:19:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:22:1
+  --> $DIR/incorrect-locations.rs:23:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:26:1
+  --> $DIR/incorrect-locations.rs:27:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:30:1
+  --> $DIR/incorrect-locations.rs:31:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:34:1
+  --> $DIR/incorrect-locations.rs:35:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:38:1
+  --> $DIR/incorrect-locations.rs:39:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr
index ee6ebabadd9..e348f0c8902 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr
@@ -1,5 +1,5 @@
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:6:1
+  --> $DIR/incorrect-locations.rs:7:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,49 +7,49 @@ LL | #[diagnostic::do_not_recommend]
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:10:1
+  --> $DIR/incorrect-locations.rs:11:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:14:1
+  --> $DIR/incorrect-locations.rs:15:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:18:1
+  --> $DIR/incorrect-locations.rs:19:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:22:1
+  --> $DIR/incorrect-locations.rs:23:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:26:1
+  --> $DIR/incorrect-locations.rs:27:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:30:1
+  --> $DIR/incorrect-locations.rs:31:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:34:1
+  --> $DIR/incorrect-locations.rs:35:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:38:1
+  --> $DIR/incorrect-locations.rs:39:1
    |
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs
index 1cf436aa2af..e716457eaed 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs
@@ -2,6 +2,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
+//@ reference: attributes.diagnostic.do_not_recommend.allowed-positions
 
 #[diagnostic::do_not_recommend]
 //~^WARN `#[diagnostic::do_not_recommend]` can only be placed
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr
index b14c68d6897..cb1da8ff8be 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `(): Root` is not satisfied
-  --> $DIR/nested.rs:21:18
+  --> $DIR/nested.rs:22:18
    |
 LL |     needs_root::<()>();
    |                  ^^ the trait `Root` is not implemented for `()`
    |
 note: required by a bound in `needs_root`
-  --> $DIR/nested.rs:18:18
+  --> $DIR/nested.rs:19:18
    |
 LL | fn needs_root<T: Root>() {}
    |                  ^^^^ required by this bound in `needs_root`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr
index b14c68d6897..cb1da8ff8be 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `(): Root` is not satisfied
-  --> $DIR/nested.rs:21:18
+  --> $DIR/nested.rs:22:18
    |
 LL |     needs_root::<()>();
    |                  ^^ the trait `Root` is not implemented for `()`
    |
 note: required by a bound in `needs_root`
-  --> $DIR/nested.rs:18:18
+  --> $DIR/nested.rs:19:18
    |
 LL | fn needs_root<T: Root>() {}
    |                  ^^^^ required by this bound in `needs_root`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/nested.rs b/tests/ui/diagnostic_namespace/do_not_recommend/nested.rs
index 6534157d1fb..3c96c760dfb 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/nested.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/nested.rs
@@ -1,6 +1,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
+//@ reference: attributes.diagnostic.do_not_recommend.intro
 
 trait Root {}
 trait DontRecommend {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr
index 884b13c17b8..dd425f1e6ee 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `*mut (): Foo` is not satisfied
-  --> $DIR/simple.rs:15:17
+  --> $DIR/simple.rs:16:17
    |
 LL |     needs_foo::<*mut ()>();
    |                 ^^^^^^^ the trait `Foo` is not implemented for `*mut ()`
    |
 note: required by a bound in `needs_foo`
-  --> $DIR/simple.rs:10:17
+  --> $DIR/simple.rs:11:17
    |
 LL | fn needs_foo<T: Foo>() {}
    |                 ^^^ required by this bound in `needs_foo`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr
index 884b13c17b8..dd425f1e6ee 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `*mut (): Foo` is not satisfied
-  --> $DIR/simple.rs:15:17
+  --> $DIR/simple.rs:16:17
    |
 LL |     needs_foo::<*mut ()>();
    |                 ^^^^^^^ the trait `Foo` is not implemented for `*mut ()`
    |
 note: required by a bound in `needs_foo`
-  --> $DIR/simple.rs:10:17
+  --> $DIR/simple.rs:11:17
    |
 LL | fn needs_foo<T: Foo>() {}
    |                 ^^^ required by this bound in `needs_foo`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
index 6bca2b724d2..a6fa7ac7949 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
@@ -1,6 +1,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
+//@ reference: attributes.diagnostic.do_not_recommend.intro
 
 trait Foo {}
 
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr
index d8605806395..d940c3fd477 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `(): Root` is not satisfied
-  --> $DIR/stacked.rs:17:18
+  --> $DIR/stacked.rs:18:18
    |
 LL |     needs_root::<()>();
    |                  ^^ the trait `Root` is not implemented for `()`
    |
 note: required by a bound in `needs_root`
-  --> $DIR/stacked.rs:14:18
+  --> $DIR/stacked.rs:15:18
    |
 LL | fn needs_root<T: Root>() {}
    |                  ^^^^ required by this bound in `needs_root`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr
index d8605806395..d940c3fd477 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `(): Root` is not satisfied
-  --> $DIR/stacked.rs:17:18
+  --> $DIR/stacked.rs:18:18
    |
 LL |     needs_root::<()>();
    |                  ^^ the trait `Root` is not implemented for `()`
    |
 note: required by a bound in `needs_root`
-  --> $DIR/stacked.rs:14:18
+  --> $DIR/stacked.rs:15:18
    |
 LL | fn needs_root<T: Root>() {}
    |                  ^^^^ required by this bound in `needs_root`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
index 842e04b9d90..fd7be35ff84 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
@@ -1,6 +1,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
+//@ reference: attributes.diagnostic.do_not_recommend.intro
 
 trait Root {}
 trait DontRecommend {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr
index 95ccbb92a89..0b07b073172 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `(): Foo` is not satisfied
-  --> $DIR/supress_suggestions_in_help.rs:21:11
+  --> $DIR/supress_suggestions_in_help.rs:22:11
    |
 LL |     check(());
    |     ----- ^^ the trait `Foo` is not implemented for `()`
@@ -8,7 +8,7 @@ LL |     check(());
    |
    = help: the trait `Foo` is implemented for `i32`
 note: required by a bound in `check`
-  --> $DIR/supress_suggestions_in_help.rs:18:18
+  --> $DIR/supress_suggestions_in_help.rs:19:18
    |
 LL | fn check(a: impl Foo) {}
    |                  ^^^ required by this bound in `check`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr
index 95ccbb92a89..0b07b073172 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `(): Foo` is not satisfied
-  --> $DIR/supress_suggestions_in_help.rs:21:11
+  --> $DIR/supress_suggestions_in_help.rs:22:11
    |
 LL |     check(());
    |     ----- ^^ the trait `Foo` is not implemented for `()`
@@ -8,7 +8,7 @@ LL |     check(());
    |
    = help: the trait `Foo` is implemented for `i32`
 note: required by a bound in `check`
-  --> $DIR/supress_suggestions_in_help.rs:18:18
+  --> $DIR/supress_suggestions_in_help.rs:19:18
    |
 LL | fn check(a: impl Foo) {}
    |                  ^^^ required by this bound in `check`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs
index 2c7c1516123..04cf8243a67 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs
@@ -1,6 +1,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
+//@ reference: attributes.diagnostic.do_not_recommend.intro
 
 trait Foo {}
 
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr
index b53febbb71a..31a1ae991ec 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr
@@ -1,11 +1,11 @@
 error[E0277]: Very important message!
-  --> $DIR/type_mismatch.rs:23:14
+  --> $DIR/type_mismatch.rs:24:14
    |
 LL |     verify::<u8>();
    |              ^^ the trait `TheImportantOne` is not implemented for `u8`
    |
 note: required by a bound in `verify`
-  --> $DIR/type_mismatch.rs:20:14
+  --> $DIR/type_mismatch.rs:21:14
    |
 LL | fn verify<T: TheImportantOne>() {}
    |              ^^^^^^^^^^^^^^^ required by this bound in `verify`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr
index b53febbb71a..31a1ae991ec 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr
@@ -1,11 +1,11 @@
 error[E0277]: Very important message!
-  --> $DIR/type_mismatch.rs:23:14
+  --> $DIR/type_mismatch.rs:24:14
    |
 LL |     verify::<u8>();
    |              ^^ the trait `TheImportantOne` is not implemented for `u8`
    |
 note: required by a bound in `verify`
-  --> $DIR/type_mismatch.rs:20:14
+  --> $DIR/type_mismatch.rs:21:14
    |
 LL | fn verify<T: TheImportantOne>() {}
    |              ^^^^^^^^^^^^^^^ required by this bound in `verify`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs
index 7f30fdb06c7..b5bd14745cd 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs
@@ -1,6 +1,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
+//@ reference: attributes.diagnostic.do_not_recommend.intro
 
 #[diagnostic::on_unimplemented(message = "Very important message!")]
 trait TheImportantOne {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr
index a8429ff60f8..7e348842e19 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/with_lifetime.rs:17:5
+  --> $DIR/with_lifetime.rs:18:5
    |
 LL | fn foo<'a>(a: &'a ()) {
    |        -- lifetime `'a` defined here
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr
index a8429ff60f8..7e348842e19 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/with_lifetime.rs:17:5
+  --> $DIR/with_lifetime.rs:18:5
    |
 LL | fn foo<'a>(a: &'a ()) {
    |        -- lifetime `'a` defined here
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs
index 6a67d83d5fe..98916ed061f 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs
@@ -1,6 +1,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
+//@ reference: attributes.diagnostic.do_not_recommend.intro
 
 trait Root {}
 trait DontRecommend {}
diff --git a/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs
new file mode 100644
index 00000000000..d1f6f4755f0
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs
@@ -0,0 +1,6 @@
+// check that `pattern_complexity_limit` is feature-gated
+
+#![pattern_complexity_limit = "42"]
+//~^ ERROR: the `#[pattern_complexity_limit]` attribute is just used for rustc unit tests
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-pattern-complexity.stderr b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr
index c05e6abb017..e6f17710e09 100644
--- a/tests/ui/feature-gates/feature-gate-pattern-complexity.stderr
+++ b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr
@@ -1,8 +1,8 @@
-error[E0658]: the `#[pattern_complexity]` attribute is just used for rustc unit tests and will never be stable
-  --> $DIR/feature-gate-pattern-complexity.rs:3:1
+error[E0658]: the `#[pattern_complexity_limit]` attribute is just used for rustc unit tests and will never be stable
+  --> $DIR/feature-gate-pattern-complexity-limit.rs:3:1
    |
-LL | #![pattern_complexity = "42"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![pattern_complexity_limit = "42"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
diff --git a/tests/ui/feature-gates/feature-gate-pattern-complexity.rs b/tests/ui/feature-gates/feature-gate-pattern-complexity.rs
deleted file mode 100644
index 43e9a00c9a7..00000000000
--- a/tests/ui/feature-gates/feature-gate-pattern-complexity.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// check that `pattern_complexity` is feature-gated
-
-#![pattern_complexity = "42"]
-//~^ ERROR: the `#[pattern_complexity]` attribute is just used for rustc unit tests
-
-fn main() {}
diff --git a/tests/ui/generic-associated-types/issue-91883.stderr b/tests/ui/generic-associated-types/issue-91883.current.stderr
index ac636ebb648..0741cf9581d 100644
--- a/tests/ui/generic-associated-types/issue-91883.stderr
+++ b/tests/ui/generic-associated-types/issue-91883.current.stderr
@@ -1,5 +1,5 @@
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/issue-91883.rs:30:24
+  --> $DIR/issue-91883.rs:34:24
    |
 LL |     type Cursor<'tx>: Cursor<'tx>
    |     ----------------------------- definition of `Cursor` from trait
@@ -8,12 +8,12 @@ LL |     type Cursor<'tx> = CursorImpl<'tx>;
    |                        ^^^^^^^^^^^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'db` as defined here
-  --> $DIR/issue-91883.rs:29:6
+  --> $DIR/issue-91883.rs:33:6
    |
 LL | impl<'db> Transaction<'db> for TransactionImpl<'db> {
    |      ^^^
 note: but lifetime parameter must outlive the lifetime `'tx` as defined here
-  --> $DIR/issue-91883.rs:30:17
+  --> $DIR/issue-91883.rs:34:17
    |
 LL |     type Cursor<'tx> = CursorImpl<'tx>;
    |                 ^^^
diff --git a/tests/ui/generic-associated-types/issue-91883.next.stderr b/tests/ui/generic-associated-types/issue-91883.next.stderr
new file mode 100644
index 00000000000..b3ed2d81b63
--- /dev/null
+++ b/tests/ui/generic-associated-types/issue-91883.next.stderr
@@ -0,0 +1,20 @@
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/issue-91883.rs:34:24
+   |
+LL |     type Cursor<'tx> = CursorImpl<'tx>;
+   |                        ^^^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the lifetime `'db` as defined here
+  --> $DIR/issue-91883.rs:33:6
+   |
+LL | impl<'db> Transaction<'db> for TransactionImpl<'db> {
+   |      ^^^
+note: but lifetime parameter must outlive the lifetime `'tx` as defined here
+  --> $DIR/issue-91883.rs:34:17
+   |
+LL |     type Cursor<'tx> = CursorImpl<'tx>;
+   |                 ^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0478`.
diff --git a/tests/ui/generic-associated-types/issue-91883.rs b/tests/ui/generic-associated-types/issue-91883.rs
index e870e08a3a2..d31e1736cf2 100644
--- a/tests/ui/generic-associated-types/issue-91883.rs
+++ b/tests/ui/generic-associated-types/issue-91883.rs
@@ -1,3 +1,7 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
 use std::fmt::Debug;
 use std::marker::PhantomData;
 
diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
index c1a78bc2388..1bbff839ffa 100644
--- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
+++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
@@ -1,5 +1,8 @@
 //@ edition:2021
 //@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 
 use std::fmt::Debug;
 
diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs b/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs
index 10c2a811243..6954a7d8067 100644
--- a/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs
+++ b/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs
@@ -1,4 +1,7 @@
 //@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 
 use std::ops::Deref;
 
diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr
index f498257e12f..f8ee6fef824 100644
--- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr
+++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr
@@ -1,4 +1,4 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 's in generic type due to conflicting requirements
+error[E0803]: cannot infer an appropriate lifetime for lifetime parameter 's in generic type due to conflicting requirements
   --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5
    |
 LL |     fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
@@ -25,4 +25,4 @@ LL |     fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0803`.
diff --git a/tests/ui/issues/issue-20831-debruijn.stderr b/tests/ui/issues/issue-20831-debruijn.stderr
index fe310998f09..bed75ed6ba2 100644
--- a/tests/ui/issues/issue-20831-debruijn.stderr
+++ b/tests/ui/issues/issue-20831-debruijn.stderr
@@ -1,4 +1,4 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> $DIR/issue-20831-debruijn.rs:28:33
    |
 LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
@@ -48,4 +48,4 @@ LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0803`.
diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs
index 81dc7285254..b87a1d2031d 100644
--- a/tests/ui/layout/debug.rs
+++ b/tests/ui/layout/debug.rs
@@ -82,3 +82,8 @@ type Impossible = (str, str); //~ ERROR: cannot be known at compilation time
 #[rustc_layout(debug)]
 union EmptyUnion {} //~ ERROR: has an unknown layout
 //~^ ERROR: unions cannot have zero fields
+
+// Test the error message of `LayoutError::TooGeneric`
+// (this error is never emitted to users).
+#[rustc_layout(debug)]
+type TooGeneric<T> = T; //~ ERROR: does not have a fixed layout
diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr
index 319c0de26a9..0daf2d3b9e7 100644
--- a/tests/ui/layout/debug.stderr
+++ b/tests/ui/layout/debug.stderr
@@ -596,12 +596,18 @@ error: the type has an unknown layout
 LL | union EmptyUnion {}
    | ^^^^^^^^^^^^^^^^
 
+error: the type `T` does not have a fixed layout
+  --> $DIR/debug.rs:89:1
+   |
+LL | type TooGeneric<T> = T;
+   | ^^^^^^^^^^^^^^^^^^
+
 error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
   --> $DIR/debug.rs:75:5
    |
 LL |     const C: () = ();
    |     ^^^^^^^^^^^
 
-error: aborting due to 19 previous errors
+error: aborting due to 20 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/layout/normalization-failure.rs b/tests/ui/layout/normalization-failure.rs
new file mode 100644
index 00000000000..c0f8710c03c
--- /dev/null
+++ b/tests/ui/layout/normalization-failure.rs
@@ -0,0 +1,57 @@
+//! This test demonstrates how `LayoutError::NormalizationFailure` can happen and why
+//! it is necessary.
+//!
+//! This code does not cause an immediate normalization error in typeck, because we
+//! don't reveal the hidden type returned by `opaque<T>` in the analysis typing mode.
+//! Instead, `<{opaque} as Project2>::Assoc2` is a *rigid projection*, because we know
+//! that `{opaque}: Project2` holds, due to the opaque type's `impl Project2` bound,
+//! but cannot normalize `<{opaque} as Project2>::Assoc2` any further.
+//!
+//! However, in the post-analysis typing mode, which is used for the layout computation,
+//! the opaque's hidden type is revealed to be `PhantomData<T>`, and now we fail to
+//! normalize `<PhantomData<T> as Project2>::Assoc2` if there is a `T: Project1` bound
+//! in the param env! This happens, because `PhantomData<T>: Project2` only holds if
+//! `<T as Project1>::Assoc1 == ()` holds. This would usually be satisfied by the
+//! blanket `impl<T> Project1 for T`, but due to the `T: Project1` bound we do not
+//! normalize `<T as Project1>::Assoc1` via the impl and treat it as rigid instead.
+//! Therefore, `PhantomData<T>: Project2` does NOT hold and normalizing
+//! `<PhantomData<T> as Project2>::Assoc2` fails.
+//!
+//! Note that this layout error can only happen when computing the layout in a generic
+//! context, which is not required for codegen, but may happen for lints, MIR optimizations,
+//! and the transmute check.
+
+use std::marker::PhantomData;
+
+trait Project1 {
+    type Assoc1;
+}
+
+impl<T> Project1 for T {
+    type Assoc1 = ();
+}
+
+trait Project2 {
+    type Assoc2;
+    fn get(self) -> Self::Assoc2;
+}
+
+impl<T: Project1<Assoc1 = ()>> Project2 for PhantomData<T> {
+    type Assoc2 = ();
+    fn get(self) -> Self::Assoc2 {}
+}
+
+fn opaque<T>() -> impl Project2 {
+    PhantomData::<T>
+}
+
+fn check<T: Project1>() {
+    unsafe {
+        std::mem::transmute::<_, ()>(opaque::<T>().get());
+        //~^ ERROR: cannot transmute
+        //~| NOTE: (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized)
+        //~| NOTE: (0 bits)
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/layout/normalization-failure.stderr b/tests/ui/layout/normalization-failure.stderr
new file mode 100644
index 00000000000..5fe38d4403a
--- /dev/null
+++ b/tests/ui/layout/normalization-failure.stderr
@@ -0,0 +1,12 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/normalization-failure.rs:50:9
+   |
+LL |         std::mem::transmute::<_, ()>(opaque::<T>().get());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `<impl Project2 as Project2>::Assoc2` (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized)
+   = note: target type: `()` (0 bits)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0512`.
diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs
index 2d1822a54ac..8f8000fe34d 100644
--- a/tests/ui/lint/invalid_from_utf8.rs
+++ b/tests/ui/lint/invalid_from_utf8.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 
 #![feature(concat_bytes)]
-
+#![feature(inherent_str_constructors)]
 #![warn(invalid_from_utf8_unchecked)]
 #![warn(invalid_from_utf8)]
 
@@ -9,7 +9,9 @@ pub fn from_utf8_unchecked_mut() {
     // Valid
     unsafe {
         std::str::from_utf8_unchecked_mut(&mut [99, 108, 105, 112, 112, 121]);
+        str::from_utf8_unchecked_mut(&mut [99, 108, 105, 112, 112, 121]);
         std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']);
+        str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']);
 
         let x = 0xA0;
         std::str::from_utf8_unchecked_mut(&mut [0xC0, x]);
@@ -19,8 +21,12 @@ pub fn from_utf8_unchecked_mut() {
     unsafe {
         std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]);
         //~^ WARN calls to `std::str::from_utf8_unchecked_mut`
+        str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]);
+        //~^ WARN calls to `str::from_utf8_unchecked_mut`
         std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
         //~^ WARN calls to `std::str::from_utf8_unchecked_mut`
+        str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
+        //~^ WARN calls to `str::from_utf8_unchecked_mut`
     }
 }
 
@@ -28,23 +34,35 @@ pub fn from_utf8_unchecked() {
     // Valid
     unsafe {
         std::str::from_utf8_unchecked(&[99, 108, 105, 112, 112, 121]);
+        str::from_utf8_unchecked(&[99, 108, 105, 112, 112, 121]);
         std::str::from_utf8_unchecked(&[b'c', b'l', b'i', b'p', b'p', b'y']);
+        str::from_utf8_unchecked(&[b'c', b'l', b'i', b'p', b'p', b'y']);
         std::str::from_utf8_unchecked(b"clippy");
+        str::from_utf8_unchecked(b"clippy");
 
         let x = 0xA0;
         std::str::from_utf8_unchecked(&[0xC0, x]);
+        str::from_utf8_unchecked(&[0xC0, x]);
     }
 
     // Invalid
     unsafe {
         std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]);
         //~^ WARN calls to `std::str::from_utf8_unchecked`
+        str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]);
+        //~^ WARN calls to `str::from_utf8_unchecked`
         std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
         //~^ WARN calls to `std::str::from_utf8_unchecked`
+        str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
+        //~^ WARN calls to `str::from_utf8_unchecked`
         std::str::from_utf8_unchecked(b"cl\x82ippy");
         //~^ WARN calls to `std::str::from_utf8_unchecked`
+        str::from_utf8_unchecked(b"cl\x82ippy");
+        //~^ WARN calls to `str::from_utf8_unchecked`
         std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy"));
         //~^ WARN calls to `std::str::from_utf8_unchecked`
+        str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy"));
+        //~^ WARN calls to `str::from_utf8_unchecked`
     }
 }
 
@@ -52,18 +70,25 @@ pub fn from_utf8_mut() {
     // Valid
     {
         std::str::from_utf8_mut(&mut [99, 108, 105, 112, 112, 121]);
+        str::from_utf8_mut(&mut [99, 108, 105, 112, 112, 121]);
         std::str::from_utf8_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']);
+        str::from_utf8_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']);
 
         let x = 0xa0;
         std::str::from_utf8_mut(&mut [0xc0, x]);
+        str::from_utf8_mut(&mut [0xc0, x]);
     }
 
     // Invalid
     {
         std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]);
         //~^ WARN calls to `std::str::from_utf8_mut`
+        str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]);
+        //~^ WARN calls to `str::from_utf8_mut`
         std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
         //~^ WARN calls to `std::str::from_utf8_mut`
+        str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
+        //~^ WARN calls to `str::from_utf8_mut`
     }
 }
 
@@ -71,23 +96,35 @@ pub fn from_utf8() {
     // Valid
     {
         std::str::from_utf8(&[99, 108, 105, 112, 112, 121]);
+        str::from_utf8(&[99, 108, 105, 112, 112, 121]);
         std::str::from_utf8(&[b'c', b'l', b'i', b'p', b'p', b'y']);
+        str::from_utf8(&[b'c', b'l', b'i', b'p', b'p', b'y']);
         std::str::from_utf8(b"clippy");
+        str::from_utf8(b"clippy");
 
         let x = 0xA0;
         std::str::from_utf8(&[0xC0, x]);
+        str::from_utf8(&[0xC0, x]);
     }
 
     // Invalid
     {
         std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]);
         //~^ WARN calls to `std::str::from_utf8`
+        str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]);
+        //~^ WARN calls to `str::from_utf8`
         std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
         //~^ WARN calls to `std::str::from_utf8`
+        str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
+        //~^ WARN calls to `str::from_utf8`
         std::str::from_utf8(b"cl\x82ippy");
         //~^ WARN calls to `std::str::from_utf8`
+        str::from_utf8(b"cl\x82ippy");
+        //~^ WARN calls to `str::from_utf8`
         std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy"));
         //~^ WARN calls to `std::str::from_utf8`
+        str::from_utf8(concat_bytes!(b"cl", b"\x82ippy"));
+        //~^ WARN calls to `str::from_utf8`
     }
 }
 
@@ -95,25 +132,39 @@ pub fn from_utf8_with_indirections() {
     let mut a = [99, 108, 130, 105, 112, 112, 121];
     std::str::from_utf8_mut(&mut a);
     //~^ WARN calls to `std::str::from_utf8_mut`
+    str::from_utf8_mut(&mut a);
+    //~^ WARN calls to `str::from_utf8_mut`
     let mut b = &mut a;
     let mut c = b;
     std::str::from_utf8_mut(c);
     //~^ WARN calls to `std::str::from_utf8_mut`
+    str::from_utf8_mut(c);
+    //~^ WARN calls to `str::from_utf8_mut`
     let mut c = &[99, 108, 130, 105, 112, 112, 121];
     std::str::from_utf8(c);
     //~^ WARN calls to `std::str::from_utf8`
+    str::from_utf8(c);
+    //~^ WARN calls to `str::from_utf8`
     const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121];
     std::str::from_utf8(&INVALID_1);
     //~^ WARN calls to `std::str::from_utf8`
+    str::from_utf8(&INVALID_1);
+    //~^ WARN calls to `str::from_utf8`
     static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121];
     std::str::from_utf8(&INVALID_2);
     //~^ WARN calls to `std::str::from_utf8`
+    str::from_utf8(&INVALID_2);
+    //~^ WARN calls to `str::from_utf8`
     const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121];
     std::str::from_utf8(INVALID_3);
     //~^ WARN calls to `std::str::from_utf8`
+    str::from_utf8(INVALID_3);
+    //~^ WARN calls to `str::from_utf8`
     const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] };
     std::str::from_utf8(INVALID_4);
     //~^ WARN calls to `std::str::from_utf8`
+    str::from_utf8(INVALID_4);
+    //~^ WARN calls to `str::from_utf8`
 }
 
 fn main() {}
diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr
index 07616e11801..715ecf56f21 100644
--- a/tests/ui/lint/invalid_from_utf8.stderr
+++ b/tests/ui/lint/invalid_from_utf8.stderr
@@ -1,5 +1,5 @@
-warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:20:9
+warning: calls to `std::str::from_utf8_unchecked_mut` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:22:9
    |
 LL |         std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^
@@ -12,48 +12,96 @@ note: the lint level is defined here
 LL | #![warn(invalid_from_utf8_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:22:9
+warning: calls to `str::from_utf8_unchecked_mut` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:24:9
+   |
+LL |         str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^
+   |                                           |
+   |                                           the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8_unchecked_mut` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:26:9
    |
 LL |         std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^
    |                                                |
    |                                                the literal was valid UTF-8 up to the 2 bytes
 
-warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:40:9
+warning: calls to `str::from_utf8_unchecked_mut` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:28:9
+   |
+LL |         str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^
+   |                                           |
+   |                                           the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8_unchecked` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:50:9
    |
 LL |         std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^
    |                                        |
    |                                        the literal was valid UTF-8 up to the 2 bytes
 
-warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:42:9
+warning: calls to `str::from_utf8_unchecked` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:52:9
+   |
+LL |         str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^
+   |                                   |
+   |                                   the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8_unchecked` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:54:9
    |
 LL |         std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^
    |                                        |
    |                                        the literal was valid UTF-8 up to the 2 bytes
 
-warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:44:9
+warning: calls to `str::from_utf8_unchecked` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:56:9
+   |
+LL |         str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^
+   |                                   |
+   |                                   the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8_unchecked` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:58:9
    |
 LL |         std::str::from_utf8_unchecked(b"cl\x82ippy");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^
    |                                       |
    |                                       the literal was valid UTF-8 up to the 2 bytes
 
-warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:46:9
+warning: calls to `str::from_utf8_unchecked` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:60:9
+   |
+LL |         str::from_utf8_unchecked(b"cl\x82ippy");
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^-------------^
+   |                                  |
+   |                                  the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8_unchecked` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:62:9
    |
 LL |         std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^
    |                                       |
    |                                       the literal was valid UTF-8 up to the 2 bytes
 
-warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:63:9
+warning: calls to `str::from_utf8_unchecked` with an invalid literal are undefined behavior
+  --> $DIR/invalid_from_utf8.rs:64:9
+   |
+LL |         str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy"));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^
+   |                                  |
+   |                                  the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8_mut` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:84:9
    |
 LL |         std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^
@@ -66,56 +114,113 @@ note: the lint level is defined here
 LL | #![warn(invalid_from_utf8)]
    |         ^^^^^^^^^^^^^^^^^
 
-warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:65:9
+warning: calls to `str::from_utf8_mut` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:86:9
+   |
+LL |         str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^
+   |                                 |
+   |                                 the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8_mut` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:88:9
    |
 LL |         std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^
    |                                      |
    |                                      the literal was valid UTF-8 up to the 2 bytes
 
-warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:83:9
+warning: calls to `str::from_utf8_mut` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:90:9
+   |
+LL |         str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^
+   |                                 |
+   |                                 the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:112:9
    |
 LL |         std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]);
    |         ^^^^^^^^^^^^^^^^^^^^^----------------------------------^
    |                              |
    |                              the literal was valid UTF-8 up to the 2 bytes
 
-warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:85:9
+warning: calls to `str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:114:9
+   |
+LL |         str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]);
+   |         ^^^^^^^^^^^^^^^^----------------------------------^
+   |                         |
+   |                         the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:116:9
    |
 LL |         std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
    |         ^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^
    |                              |
    |                              the literal was valid UTF-8 up to the 2 bytes
 
-warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:87:9
+warning: calls to `str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:118:9
+   |
+LL |         str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
+   |         ^^^^^^^^^^^^^^^^---------------------------------------------^
+   |                         |
+   |                         the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:120:9
    |
 LL |         std::str::from_utf8(b"cl\x82ippy");
    |         ^^^^^^^^^^^^^^^^^^^^-------------^
    |                             |
    |                             the literal was valid UTF-8 up to the 2 bytes
 
-warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:89:9
+warning: calls to `str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:122:9
+   |
+LL |         str::from_utf8(b"cl\x82ippy");
+   |         ^^^^^^^^^^^^^^^-------------^
+   |                        |
+   |                        the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:124:9
    |
 LL |         std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy"));
    |         ^^^^^^^^^^^^^^^^^^^^---------------------------------^
    |                             |
    |                             the literal was valid UTF-8 up to the 2 bytes
 
-warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:96:5
+warning: calls to `str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:126:9
+   |
+LL |         str::from_utf8(concat_bytes!(b"cl", b"\x82ippy"));
+   |         ^^^^^^^^^^^^^^^---------------------------------^
+   |                        |
+   |                        the literal was valid UTF-8 up to the 2 bytes
+
+warning: calls to `std::str::from_utf8_mut` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:133:5
    |
 LL |     let mut a = [99, 108, 130, 105, 112, 112, 121];
    |                 ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
 LL |     std::str::from_utf8_mut(&mut a);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:100:5
+warning: calls to `str::from_utf8_mut` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:135:5
+   |
+LL |     let mut a = [99, 108, 130, 105, 112, 112, 121];
+   |                 ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+...
+LL |     str::from_utf8_mut(&mut a);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8_mut` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:139:5
    |
 LL |     let mut a = [99, 108, 130, 105, 112, 112, 121];
    |                 ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
@@ -123,45 +228,99 @@ LL |     let mut a = [99, 108, 130, 105, 112, 112, 121];
 LL |     std::str::from_utf8_mut(c);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:103:5
+warning: calls to `str::from_utf8_mut` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:141:5
+   |
+LL |     let mut a = [99, 108, 130, 105, 112, 112, 121];
+   |                 ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+...
+LL |     str::from_utf8_mut(c);
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:144:5
    |
 LL |     let mut c = &[99, 108, 130, 105, 112, 112, 121];
    |                  ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
 LL |     std::str::from_utf8(c);
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:106:5
+warning: calls to `str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:146:5
+   |
+LL |     let mut c = &[99, 108, 130, 105, 112, 112, 121];
+   |                  ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+...
+LL |     str::from_utf8(c);
+   |     ^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:149:5
    |
 LL |     const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121];
    |                                ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
 LL |     std::str::from_utf8(&INVALID_1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:109:5
+warning: calls to `str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:151:5
+   |
+LL |     const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121];
+   |                                ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+...
+LL |     str::from_utf8(&INVALID_1);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:154:5
    |
 LL |     static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121];
    |                                 ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
 LL |     std::str::from_utf8(&INVALID_2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:112:5
+warning: calls to `str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:156:5
+   |
+LL |     static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121];
+   |                                 ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+...
+LL |     str::from_utf8(&INVALID_2);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:159:5
    |
 LL |     const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121];
    |                                          ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
 LL |     std::str::from_utf8(INVALID_3);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:115:5
+warning: calls to `str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:161:5
+   |
+LL |     const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121];
+   |                                          ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+...
+LL |     str::from_utf8(INVALID_3);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:164:5
    |
 LL |     const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] };
    |                                            ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
 LL |     std::str::from_utf8(INVALID_4);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: 19 warnings emitted
+warning: calls to `str::from_utf8` with an invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:166:5
+   |
+LL |     const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] };
+   |                                            ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+...
+LL |     str::from_utf8(INVALID_4);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 38 warnings emitted
 
diff --git a/tests/ui/macros/block-to-expr-metavar.rs b/tests/ui/macros/block-to-expr-metavar.rs
new file mode 100644
index 00000000000..04f10ad0f98
--- /dev/null
+++ b/tests/ui/macros/block-to-expr-metavar.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+//
+// A test case where a `block` fragment specifier is interpreted as an `expr`
+// fragment specifier. It's an interesting case for the handling of invisible
+// delimiters.
+
+macro_rules! m_expr {
+    ($e:expr) => { const _CURRENT: u32 = $e; };
+}
+
+macro_rules! m_block {
+    ($b:block) => ( m_expr!($b); );
+}
+
+fn main() {
+    m_block!({ 1 });
+}
diff --git a/tests/ui/macros/macro-interpolation.rs b/tests/ui/macros/macro-interpolation.rs
index 48c1f19e777..b5d2322c805 100644
--- a/tests/ui/macros/macro-interpolation.rs
+++ b/tests/ui/macros/macro-interpolation.rs
@@ -19,7 +19,7 @@ macro_rules! qpath {
 
     (ty, <$type:ty as $trait:ty>::$name:ident) => {
         <$type as $trait>::$name
-        //~^ ERROR expected identifier, found `!`
+        //~^ ERROR expected identifier, found metavariable
     };
 }
 
diff --git a/tests/ui/macros/macro-interpolation.stderr b/tests/ui/macros/macro-interpolation.stderr
index e6b39dfef85..bc24a158612 100644
--- a/tests/ui/macros/macro-interpolation.stderr
+++ b/tests/ui/macros/macro-interpolation.stderr
@@ -1,8 +1,8 @@
-error: expected identifier, found `!`
+error: expected identifier, found metavariable
   --> $DIR/macro-interpolation.rs:21:19
    |
 LL |         <$type as $trait>::$name
-   |                   ^^^^^^ expected identifier
+   |                   ^^^^^^ expected identifier, found metavariable
 ...
 LL |     let _: qpath!(ty, <str as !>::Owned);
    |            -----------------------------
diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs
index 016e4def284..6cf9d54e826 100644
--- a/tests/ui/macros/syntax-error-recovery.rs
+++ b/tests/ui/macros/syntax-error-recovery.rs
@@ -9,8 +9,8 @@ macro_rules! values {
         }
     };
 }
-//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
-//~| ERROR macro expansion ignores type `(String)` and any tokens following
+//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable
+//~| ERROR macro expansion ignores `ty` metavariable and any tokens following
 
 values!(STRING(1) as (String) => cfg(test),);
 //~^ ERROR expected one of `!` or `::`, found `<eof>`
diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr
index 3cfbd8ce82b..61758fb9d7d 100644
--- a/tests/ui/macros/syntax-error-recovery.stderr
+++ b/tests/ui/macros/syntax-error-recovery.stderr
@@ -1,4 +1,4 @@
-error: expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
+error: expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable
   --> $DIR/syntax-error-recovery.rs:7:26
    |
 LL |                 $token $($inner)? = $value,
@@ -10,7 +10,7 @@ LL | values!(STRING(1) as (String) => cfg(test),);
    = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
    = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: macro expansion ignores type `(String)` and any tokens following
+error: macro expansion ignores `ty` metavariable and any tokens following
   --> $DIR/syntax-error-recovery.rs:7:26
    |
 LL |                 $token $($inner)? = $value,
diff --git a/tests/ui/nll/normalization-bounds-error.stderr b/tests/ui/nll/normalization-bounds-error.stderr
index d4254881863..47d2663313d 100644
--- a/tests/ui/nll/normalization-bounds-error.stderr
+++ b/tests/ui/nll/normalization-bounds-error.stderr
@@ -1,4 +1,4 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements
+error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements
   --> $DIR/normalization-bounds-error.rs:12:31
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
@@ -36,4 +36,4 @@ LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0803`.
diff --git a/tests/ui/parser/macro/issue-37113.rs b/tests/ui/parser/macro/issue-37113.rs
index 0044aa5610f..e0957542f8f 100644
--- a/tests/ui/parser/macro/issue-37113.rs
+++ b/tests/ui/parser/macro/issue-37113.rs
@@ -1,7 +1,7 @@
 macro_rules! test_macro {
     ( $( $t:ty ),* $(),*) => {
         enum SomeEnum {
-            $( $t, )* //~ ERROR expected identifier, found `String`
+            $( $t, )* //~ ERROR expected identifier, found metavariable
         };
     };
 }
diff --git a/tests/ui/parser/macro/issue-37113.stderr b/tests/ui/parser/macro/issue-37113.stderr
index 1f2fe23106a..560329df5cc 100644
--- a/tests/ui/parser/macro/issue-37113.stderr
+++ b/tests/ui/parser/macro/issue-37113.stderr
@@ -1,10 +1,10 @@
-error: expected identifier, found `String`
+error: expected identifier, found metavariable
   --> $DIR/issue-37113.rs:4:16
    |
 LL |         enum SomeEnum {
    |              -------- while parsing this enum
 LL |             $( $t, )*
-   |                ^^ expected identifier
+   |                ^^ expected identifier, found metavariable
 ...
 LL |     test_macro!(String,);
    |     -------------------- in this macro invocation
diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.rs b/tests/ui/parser/macro/trait-object-macro-matcher.rs
index 560195977d0..d4ec199070e 100644
--- a/tests/ui/parser/macro/trait-object-macro-matcher.rs
+++ b/tests/ui/parser/macro/trait-object-macro-matcher.rs
@@ -10,5 +10,6 @@ macro_rules! m {
 fn main() {
     m!('static);
     //~^ ERROR lifetime in trait object type must be followed by `+`
+    //~| ERROR lifetime in trait object type must be followed by `+`
     //~| ERROR at least one trait is required for an object type
 }
diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.stderr b/tests/ui/parser/macro/trait-object-macro-matcher.stderr
index 40082564bad..81dca6f71c4 100644
--- a/tests/ui/parser/macro/trait-object-macro-matcher.stderr
+++ b/tests/ui/parser/macro/trait-object-macro-matcher.stderr
@@ -4,12 +4,20 @@ error: lifetime in trait object type must be followed by `+`
 LL |     m!('static);
    |        ^^^^^^^
 
+error: lifetime in trait object type must be followed by `+`
+  --> $DIR/trait-object-macro-matcher.rs:11:8
+   |
+LL |     m!('static);
+   |        ^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error[E0224]: at least one trait is required for an object type
   --> $DIR/trait-object-macro-matcher.rs:11:8
    |
 LL |     m!('static);
    |        ^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0224`.
diff --git a/tests/ui/parser/raw/raw-idents.rs b/tests/ui/parser/raw/raw-idents.rs
new file mode 100644
index 00000000000..93015ee6c49
--- /dev/null
+++ b/tests/ui/parser/raw/raw-idents.rs
@@ -0,0 +1,158 @@
+//@ check-pass
+//@ revisions:e2015 e2018 e2021 e2024
+//@[e2015] edition:2015
+//@[e2018] edition:2018
+//@[e2021] edition:2021
+//@[e2024] edition:2024
+
+// Ensure that all (usable as identifier) keywords work as raw identifiers in all positions.
+// This was motivated by issue #137128, where `r#move`/`r#static`` did not work as `const` names
+// due to a parser check not acounting for raw identifiers.
+
+#![crate_type = "lib"]
+#![allow(dead_code, nonstandard_style)]
+
+// NOTE: It is vital to only use a `tt` fragment to avoid confusing
+// the parser with nonterminals that can mask bugs.
+
+macro_rules! tests {
+    ($kw:tt) => {
+        mod $kw {
+            mod const_item {
+                const $kw: () = ();
+            }
+            mod static_item {
+                static $kw: () = ();
+            }
+            mod fn_item {
+                fn $kw() {}
+            }
+            mod mod_and_use_item {
+                mod $kw {
+                    use super::$kw;
+                }
+            }
+            mod ty_alias_item {
+                type $kw = ();
+            }
+            mod struct_item {
+                struct $kw { $kw: () }
+            }
+            mod enum_item {
+                enum $kw { $kw }
+            }
+            mod union_item {
+                union $kw { $kw: () }
+            }
+            mod trait_item {
+                trait $kw {
+                    fn $kw() {}
+                }
+            }
+            mod generics_and_impl {
+                struct A<$kw>($kw);
+                enum B<$kw> { A($kw) }
+                trait Tr<$kw> {
+                    type $kw;
+                }
+
+                impl<$kw> Tr<$kw> for A<$kw> {
+                    type $kw = ();
+                }
+                impl<$kw> B<$kw> {}
+            }
+            mod extern_crate {
+                #[cfg(any())]
+                extern crate $kw;
+            }
+            mod body {
+                fn expr() {
+                    let $kw = 0;
+                    let b = $kw;
+                    assert_eq!($kw, b);
+                    type $kw = ();
+                    let $kw: $kw = ();
+                    let _ = $kw as $kw;
+                }
+                fn pat_const() {
+                    const $kw: u8 = 0;
+
+                    // Ensure that $kw actually matches the constant.
+                    #[forbid(unreachable_patterns)]
+                    match 1 {
+                        $kw => {}
+                        _ => {}
+                    }
+                }
+                fn pat_binding() {
+                    match 1 {
+                        $kw => {}
+                        _ => {}
+                    }
+                }
+            }
+        }
+    };
+}
+
+tests!(r#break);
+tests!(r#const);
+tests!(r#continue);
+tests!(r#else);
+tests!(r#enum);
+tests!(r#extern);
+tests!(r#false);
+tests!(r#fn);
+tests!(r#for);
+tests!(r#if);
+tests!(r#impl);
+tests!(r#in);
+tests!(r#let);
+tests!(r#loop);
+tests!(r#match);
+tests!(r#mod);
+tests!(r#move);
+tests!(r#mut);
+tests!(r#pub);
+tests!(r#ref);
+tests!(r#return);
+tests!(r#static);
+tests!(r#struct);
+tests!(r#trait);
+tests!(r#true);
+tests!(r#type);
+tests!(r#unsafe);
+tests!(r#use);
+tests!(r#where);
+tests!(r#while);
+tests!(r#abstract);
+tests!(r#become);
+tests!(r#box);
+tests!(r#do);
+tests!(r#final);
+tests!(r#macro);
+tests!(r#override);
+tests!(r#priv);
+tests!(r#typeof);
+tests!(r#unsized);
+tests!(r#virtual);
+tests!(r#yield);
+tests!(r#async);
+tests!(r#await);
+tests!(r#dyn);
+tests!(r#gen);
+tests!(r#try);
+
+// Weak keywords:
+tests!(auto);
+tests!(builtin);
+tests!(catch);
+tests!(default);
+tests!(macro_rules);
+tests!(raw);
+tests!(reuse);
+tests!(contract_ensures);
+tests!(contract_requires);
+tests!(safe);
+tests!(union);
+tests!(yeet);
diff --git a/tests/ui/pattern/complexity_limit.rs b/tests/ui/pattern/complexity_limit.rs
index c9a3f99bccd..7c127820511 100644
--- a/tests/ui/pattern/complexity_limit.rs
+++ b/tests/ui/pattern/complexity_limit.rs
@@ -1,5 +1,5 @@
 #![feature(rustc_attrs)]
-#![pattern_complexity = "10000"]
+#![pattern_complexity_limit = "10000"]
 
 #[derive(Default)]
 struct BaseCommand {
diff --git a/tests/ui/pattern/usefulness/issue-118437-exponential-time-on-diagonal-match.rs b/tests/ui/pattern/usefulness/issue-118437-exponential-time-on-diagonal-match.rs
index 783512d5cca..44d1586ce4f 100644
--- a/tests/ui/pattern/usefulness/issue-118437-exponential-time-on-diagonal-match.rs
+++ b/tests/ui/pattern/usefulness/issue-118437-exponential-time-on-diagonal-match.rs
@@ -1,5 +1,5 @@
 #![feature(rustc_attrs)]
-#![pattern_complexity = "61"]
+#![pattern_complexity_limit = "61"]
 
 //@ check-pass
 struct BaseCommand {
diff --git a/tests/ui/process/process-sigpipe.rs b/tests/ui/process/process-sigpipe.rs
index 453e53379fc..3ecf271599d 100644
--- a/tests/ui/process/process-sigpipe.rs
+++ b/tests/ui/process/process-sigpipe.rs
@@ -9,9 +9,9 @@
 // Make sure that these behaviors don't get inherited to children
 // spawned via std::process, since they're needed for traditional UNIX
 // filter behavior.
-// This test checks that `while echo y ; do : ; done | head` terminates
-// (instead of running forever), and that it does not print an error
-// message about a broken pipe.
+// This test checks that `yes` or `while echo y ; do : ; done | head`
+// terminates (instead of running forever), and that it does not print an
+// error message about a broken pipe.
 
 //@ ignore-vxworks no 'sh'
 //@ ignore-fuchsia no 'sh'
@@ -22,14 +22,21 @@ use std::process;
 use std::thread;
 
 fn main() {
-    // Just in case `yes` doesn't check for EPIPE...
+    // Just in case `yes` or `while-echo` doesn't check for EPIPE...
     thread::spawn(|| {
         thread::sleep_ms(5000);
         process::exit(1);
     });
+    // QNX Neutrino does not have `yes`. Therefore, use `while-echo` for `nto`
+    // and `yes` for other platforms.
+    let command = if cfg!(target_os = "nto") {
+        "while echo y ; do : ; done | head"
+    } else {
+        "yes | head"
+    };
     let output = process::Command::new("sh")
         .arg("-c")
-        .arg("while echo y ; do : ; done | head")
+        .arg(command)
         .output()
         .unwrap();
     assert!(output.status.success());
diff --git a/tests/ui/regions/regions-normalize-in-where-clause-list.stderr b/tests/ui/regions/regions-normalize-in-where-clause-list.stderr
index 2e76333e26f..ca9ceeeeff3 100644
--- a/tests/ui/regions/regions-normalize-in-where-clause-list.stderr
+++ b/tests/ui/regions/regions-normalize-in-where-clause-list.stderr
@@ -1,4 +1,4 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> $DIR/regions-normalize-in-where-clause-list.rs:24:4
    |
 LL | fn bar<'a, 'b>()
@@ -24,4 +24,4 @@ LL | fn bar<'a, 'b>()
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0803`.
diff --git a/tests/ui/regions/resolve-re-error-ice.stderr b/tests/ui/regions/resolve-re-error-ice.stderr
index 41c5f0fa92e..f463a97c5bc 100644
--- a/tests/ui/regions/resolve-re-error-ice.stderr
+++ b/tests/ui/regions/resolve-re-error-ice.stderr
@@ -1,4 +1,4 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter '_ in generic type due to conflicting requirements
+error[E0803]: cannot infer an appropriate lifetime for lifetime parameter '_ in generic type due to conflicting requirements
   --> $DIR/resolve-re-error-ice.rs:12:5
    |
 LL |     fn key_set(&self) -> Subject<'a, Keys<K, V>, (), R> {
@@ -34,4 +34,4 @@ LL | struct Subject<'a, T, V, R>(PhantomData<(&'a T, V, R)>);
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0803`.
diff --git a/tests/ui/simd-abi-checks-empty-list.rs b/tests/ui/simd-abi-checks-empty-list.rs
index fd4957b5b93..ca0889364fc 100644
--- a/tests/ui/simd-abi-checks-empty-list.rs
+++ b/tests/ui/simd-abi-checks-empty-list.rs
@@ -1,15 +1,14 @@
+//@ add-core-stubs
 //@ needs-llvm-components: sparc
 //@ compile-flags: --target=sparc-unknown-none-elf --crate-type=rlib
 //@ build-pass
 //@ ignore-pass (test emits codegen-time warnings)
 #![no_core]
-#![feature(no_core, lang_items, repr_simd)]
+#![feature(no_core, repr_simd)]
 #![allow(improper_ctypes_definitions)]
-#[lang = "sized"]
-trait Sized {}
 
-#[lang = "copy"]
-trait Copy {}
+extern crate minicore;
+use minicore::*;
 
 #[repr(simd)]
 pub struct SimdVec([i32; 4]);
diff --git a/tests/ui/simd-abi-checks-empty-list.stderr b/tests/ui/simd-abi-checks-empty-list.stderr
index 91c61884fd0..111dda42f33 100644
--- a/tests/ui/simd-abi-checks-empty-list.stderr
+++ b/tests/ui/simd-abi-checks-empty-list.stderr
@@ -1,5 +1,5 @@
 warning: this function definition uses SIMD vector type `SimdVec` which is not currently supported with the chosen ABI
-  --> $DIR/simd-abi-checks-empty-list.rs:17:1
+  --> $DIR/simd-abi-checks-empty-list.rs:16:1
    |
 LL | pub extern "C" fn pass_by_vec(_: SimdVec) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -12,7 +12,7 @@ warning: 1 warning emitted
 
 Future incompatibility report: Future breakage diagnostic:
 warning: this function definition uses SIMD vector type `SimdVec` which is not currently supported with the chosen ABI
-  --> $DIR/simd-abi-checks-empty-list.rs:17:1
+  --> $DIR/simd-abi-checks-empty-list.rs:16:1
    |
 LL | pub extern "C" fn pass_by_vec(_: SimdVec) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
diff --git a/tests/ui/simd-abi-checks-s390x.rs b/tests/ui/simd-abi-checks-s390x.rs
index 7e408f66561..424ac00edcf 100644
--- a/tests/ui/simd-abi-checks-s390x.rs
+++ b/tests/ui/simd-abi-checks-s390x.rs
@@ -1,3 +1,4 @@
+//@ add-core-stubs
 //@ revisions: z10 z13_no_vector z13_soft_float
 //@ build-fail
 //@[z10] compile-flags: --target s390x-unknown-linux-gnu
@@ -8,20 +9,14 @@
 //@[z13_soft_float] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector,+soft-float
 //@[z13_soft_float] needs-llvm-components: systemz
 
-#![feature(no_core, lang_items, repr_simd, s390x_target_feature)]
+#![feature(no_core, repr_simd, s390x_target_feature)]
 #![no_core]
 #![crate_type = "lib"]
 #![allow(non_camel_case_types, improper_ctypes_definitions)]
 #![deny(abi_unsupported_vector_types)]
 
-#[lang = "sized"]
-pub trait Sized {}
-#[lang = "copy"]
-pub trait Copy {}
-#[lang = "freeze"]
-pub trait Freeze {}
-
-impl<T: Copy, const N: usize> Copy for [T; N] {}
+extern crate minicore;
+use minicore::*;
 
 #[repr(simd)]
 pub struct i8x8([i8; 8]);
@@ -34,8 +29,6 @@ pub struct Wrapper<T>(T);
 #[repr(transparent)]
 pub struct TransparentWrapper<T>(T);
 
-impl Copy for i8 {}
-impl Copy for i64 {}
 impl Copy for i8x8 {}
 impl Copy for i8x16 {}
 impl Copy for i8x32 {}
diff --git a/tests/ui/simd-abi-checks-s390x.z10.stderr b/tests/ui/simd-abi-checks-s390x.z10.stderr
index ab97299e84a..d2f7abb7c32 100644
--- a/tests/ui/simd-abi-checks-s390x.z10.stderr
+++ b/tests/ui/simd-abi-checks-s390x.z10.stderr
@@ -1,5 +1,5 @@
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:46:1
+  --> $DIR/simd-abi-checks-s390x.rs:39:1
    |
 LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -8,13 +8,13 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:52:1
+  --> $DIR/simd-abi-checks-s390x.rs:45:1
    |
 LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -24,7 +24,7 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:99:1
+  --> $DIR/simd-abi-checks-s390x.rs:92:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret_small(
 LL | |     x: &TransparentWrapper<i8x8>,
@@ -36,7 +36,7 @@ LL | | ) -> TransparentWrapper<i8x8> {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:107:1
+  --> $DIR/simd-abi-checks-s390x.rs:100:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret(
 LL | |     x: &TransparentWrapper<i8x16>,
@@ -48,7 +48,7 @@ LL | | ) -> TransparentWrapper<i8x16> {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:123:1
+  --> $DIR/simd-abi-checks-s390x.rs:116:1
    |
 LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -58,7 +58,7 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:129:1
+  --> $DIR/simd-abi-checks-s390x.rs:122:1
    |
 LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -68,7 +68,7 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:141:1
+  --> $DIR/simd-abi-checks-s390x.rs:134:1
    |
 LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -78,7 +78,7 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:147:1
+  --> $DIR/simd-abi-checks-s390x.rs:140:1
    |
 LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -88,7 +88,7 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:159:1
+  --> $DIR/simd-abi-checks-s390x.rs:152:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -98,7 +98,7 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:165:1
+  --> $DIR/simd-abi-checks-s390x.rs:158:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -111,7 +111,7 @@ error: aborting due to 10 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:46:1
+  --> $DIR/simd-abi-checks-s390x.rs:39:1
    |
 LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -120,14 +120,14 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:52:1
+  --> $DIR/simd-abi-checks-s390x.rs:45:1
    |
 LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -136,14 +136,14 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:99:1
+  --> $DIR/simd-abi-checks-s390x.rs:92:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret_small(
 LL | |     x: &TransparentWrapper<i8x8>,
@@ -154,14 +154,14 @@ LL | | ) -> TransparentWrapper<i8x8> {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:107:1
+  --> $DIR/simd-abi-checks-s390x.rs:100:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret(
 LL | |     x: &TransparentWrapper<i8x16>,
@@ -172,14 +172,14 @@ LL | | ) -> TransparentWrapper<i8x16> {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:123:1
+  --> $DIR/simd-abi-checks-s390x.rs:116:1
    |
 LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -188,14 +188,14 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:129:1
+  --> $DIR/simd-abi-checks-s390x.rs:122:1
    |
 LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -204,14 +204,14 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:141:1
+  --> $DIR/simd-abi-checks-s390x.rs:134:1
    |
 LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -220,14 +220,14 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:147:1
+  --> $DIR/simd-abi-checks-s390x.rs:140:1
    |
 LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -236,14 +236,14 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:159:1
+  --> $DIR/simd-abi-checks-s390x.rs:152:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -252,14 +252,14 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:165:1
+  --> $DIR/simd-abi-checks-s390x.rs:158:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -268,7 +268,7 @@ LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>)
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr b/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr
index ab97299e84a..d2f7abb7c32 100644
--- a/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr
+++ b/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr
@@ -1,5 +1,5 @@
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:46:1
+  --> $DIR/simd-abi-checks-s390x.rs:39:1
    |
 LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -8,13 +8,13 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:52:1
+  --> $DIR/simd-abi-checks-s390x.rs:45:1
    |
 LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -24,7 +24,7 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:99:1
+  --> $DIR/simd-abi-checks-s390x.rs:92:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret_small(
 LL | |     x: &TransparentWrapper<i8x8>,
@@ -36,7 +36,7 @@ LL | | ) -> TransparentWrapper<i8x8> {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:107:1
+  --> $DIR/simd-abi-checks-s390x.rs:100:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret(
 LL | |     x: &TransparentWrapper<i8x16>,
@@ -48,7 +48,7 @@ LL | | ) -> TransparentWrapper<i8x16> {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:123:1
+  --> $DIR/simd-abi-checks-s390x.rs:116:1
    |
 LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -58,7 +58,7 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:129:1
+  --> $DIR/simd-abi-checks-s390x.rs:122:1
    |
 LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -68,7 +68,7 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:141:1
+  --> $DIR/simd-abi-checks-s390x.rs:134:1
    |
 LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -78,7 +78,7 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:147:1
+  --> $DIR/simd-abi-checks-s390x.rs:140:1
    |
 LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -88,7 +88,7 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:159:1
+  --> $DIR/simd-abi-checks-s390x.rs:152:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -98,7 +98,7 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:165:1
+  --> $DIR/simd-abi-checks-s390x.rs:158:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -111,7 +111,7 @@ error: aborting due to 10 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:46:1
+  --> $DIR/simd-abi-checks-s390x.rs:39:1
    |
 LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -120,14 +120,14 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:52:1
+  --> $DIR/simd-abi-checks-s390x.rs:45:1
    |
 LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -136,14 +136,14 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:99:1
+  --> $DIR/simd-abi-checks-s390x.rs:92:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret_small(
 LL | |     x: &TransparentWrapper<i8x8>,
@@ -154,14 +154,14 @@ LL | | ) -> TransparentWrapper<i8x8> {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:107:1
+  --> $DIR/simd-abi-checks-s390x.rs:100:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret(
 LL | |     x: &TransparentWrapper<i8x16>,
@@ -172,14 +172,14 @@ LL | | ) -> TransparentWrapper<i8x16> {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:123:1
+  --> $DIR/simd-abi-checks-s390x.rs:116:1
    |
 LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -188,14 +188,14 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:129:1
+  --> $DIR/simd-abi-checks-s390x.rs:122:1
    |
 LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -204,14 +204,14 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:141:1
+  --> $DIR/simd-abi-checks-s390x.rs:134:1
    |
 LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -220,14 +220,14 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:147:1
+  --> $DIR/simd-abi-checks-s390x.rs:140:1
    |
 LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -236,14 +236,14 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:159:1
+  --> $DIR/simd-abi-checks-s390x.rs:152:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -252,14 +252,14 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:165:1
+  --> $DIR/simd-abi-checks-s390x.rs:158:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -268,7 +268,7 @@ LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>)
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr b/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr
index ab97299e84a..d2f7abb7c32 100644
--- a/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr
+++ b/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr
@@ -1,5 +1,5 @@
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:46:1
+  --> $DIR/simd-abi-checks-s390x.rs:39:1
    |
 LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -8,13 +8,13 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:52:1
+  --> $DIR/simd-abi-checks-s390x.rs:45:1
    |
 LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -24,7 +24,7 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:99:1
+  --> $DIR/simd-abi-checks-s390x.rs:92:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret_small(
 LL | |     x: &TransparentWrapper<i8x8>,
@@ -36,7 +36,7 @@ LL | | ) -> TransparentWrapper<i8x8> {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:107:1
+  --> $DIR/simd-abi-checks-s390x.rs:100:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret(
 LL | |     x: &TransparentWrapper<i8x16>,
@@ -48,7 +48,7 @@ LL | | ) -> TransparentWrapper<i8x16> {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:123:1
+  --> $DIR/simd-abi-checks-s390x.rs:116:1
    |
 LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -58,7 +58,7 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:129:1
+  --> $DIR/simd-abi-checks-s390x.rs:122:1
    |
 LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -68,7 +68,7 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:141:1
+  --> $DIR/simd-abi-checks-s390x.rs:134:1
    |
 LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -78,7 +78,7 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:147:1
+  --> $DIR/simd-abi-checks-s390x.rs:140:1
    |
 LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -88,7 +88,7 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:159:1
+  --> $DIR/simd-abi-checks-s390x.rs:152:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -98,7 +98,7 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:165:1
+  --> $DIR/simd-abi-checks-s390x.rs:158:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -111,7 +111,7 @@ error: aborting due to 10 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:46:1
+  --> $DIR/simd-abi-checks-s390x.rs:39:1
    |
 LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -120,14 +120,14 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:52:1
+  --> $DIR/simd-abi-checks-s390x.rs:45:1
    |
 LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -136,14 +136,14 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:99:1
+  --> $DIR/simd-abi-checks-s390x.rs:92:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret_small(
 LL | |     x: &TransparentWrapper<i8x8>,
@@ -154,14 +154,14 @@ LL | | ) -> TransparentWrapper<i8x8> {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:107:1
+  --> $DIR/simd-abi-checks-s390x.rs:100:1
    |
 LL | / extern "C" fn vector_transparent_wrapper_ret(
 LL | |     x: &TransparentWrapper<i8x16>,
@@ -172,14 +172,14 @@ LL | | ) -> TransparentWrapper<i8x16> {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:123:1
+  --> $DIR/simd-abi-checks-s390x.rs:116:1
    |
 LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -188,14 +188,14 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:129:1
+  --> $DIR/simd-abi-checks-s390x.rs:122:1
    |
 LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -204,14 +204,14 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:141:1
+  --> $DIR/simd-abi-checks-s390x.rs:134:1
    |
 LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -220,14 +220,14 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:147:1
+  --> $DIR/simd-abi-checks-s390x.rs:140:1
    |
 LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -236,14 +236,14 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:159:1
+  --> $DIR/simd-abi-checks-s390x.rs:152:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -252,14 +252,14 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
-  --> $DIR/simd-abi-checks-s390x.rs:165:1
+  --> $DIR/simd-abi-checks-s390x.rs:158:1
    |
 LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -268,7 +268,7 @@ LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>)
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
 note: the lint level is defined here
-  --> $DIR/simd-abi-checks-s390x.rs:15:9
+  --> $DIR/simd-abi-checks-s390x.rs:16:9
    |
 LL | #![deny(abi_unsupported_vector_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/sse-abi-checks.rs b/tests/ui/sse-simd-abi-checks.rs
index 3c9fe1f0ddb..396e9bf1318 100644
--- a/tests/ui/sse-abi-checks.rs
+++ b/tests/ui/sse-simd-abi-checks.rs
@@ -1,6 +1,8 @@
 //! Ensure we trigger abi_unsupported_vector_types for target features that are usually enabled
-//! on a target, but disabled in this file via a `-C` flag.
-//@ compile-flags: --crate-type=rlib --target=i586-unknown-linux-gnu -C target-feature=-sse,-sse2
+//! on a target via the base CPU, but disabled in this file via a `-C` flag.
+//@ compile-flags: --crate-type=rlib --target=i586-unknown-linux-gnu
+//@ compile-flags: -Ctarget-cpu=pentium4 -C target-feature=-sse,-sse2
+//@ add-core-stubs
 //@ build-pass
 //@ ignore-pass (test emits codegen-time warnings)
 //@ needs-llvm-components: x86
@@ -8,11 +10,8 @@
 #![no_core]
 #![allow(improper_ctypes_definitions)]
 
-#[lang = "sized"]
-trait Sized {}
-
-#[lang = "copy"]
-trait Copy {}
+extern crate minicore;
+use minicore::*;
 
 #[repr(simd)]
 pub struct SseVector([i64; 2]);
diff --git a/tests/ui/sse-abi-checks.stderr b/tests/ui/sse-simd-abi-checks.stderr
index 712322a5848..95486f480d2 100644
--- a/tests/ui/sse-abi-checks.stderr
+++ b/tests/ui/sse-simd-abi-checks.stderr
@@ -1,5 +1,5 @@
 warning: this function definition uses SIMD vector type `SseVector` which (with the chosen ABI) requires the `sse` target feature, which is not enabled
-  --> $DIR/sse-abi-checks.rs:21:1
+  --> $DIR/sse-simd-abi-checks.rs:20:1
    |
 LL | pub unsafe extern "C" fn f(_: SseVector) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
@@ -13,7 +13,7 @@ warning: 1 warning emitted
 
 Future incompatibility report: Future breakage diagnostic:
 warning: this function definition uses SIMD vector type `SseVector` which (with the chosen ABI) requires the `sse` target feature, which is not enabled
-  --> $DIR/sse-abi-checks.rs:21:1
+  --> $DIR/sse-simd-abi-checks.rs:20:1
    |
 LL | pub unsafe extern "C" fn f(_: SseVector) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
diff --git a/tests/ui/static/static-lifetime.stderr b/tests/ui/static/static-lifetime.stderr
index 7a956dbfeef..9b5869fd0dc 100644
--- a/tests/ui/static/static-lifetime.stderr
+++ b/tests/ui/static/static-lifetime.stderr
@@ -11,7 +11,7 @@ LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
    |      ^^
    = note: but lifetime parameter must outlive the static lifetime
 
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> $DIR/static-lifetime.rs:3:34
    |
 LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
@@ -38,5 +38,5 @@ LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0478, E0495.
+Some errors have detailed explanations: E0478, E0803.
 For more information about an error, try `rustc --explain E0478`.
diff --git a/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.rs b/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.rs
new file mode 100644
index 00000000000..71d90ddd935
--- /dev/null
+++ b/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.rs
@@ -0,0 +1,6 @@
+#![feature(default_field_values)]
+struct A<'a> { //~ ERROR lifetime parameter `'a` is never used
+    x: Vec<A> = Vec::new(), //~ ERROR missing lifetime specifier
+}
+
+fn main() {}
diff --git a/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.stderr b/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.stderr
new file mode 100644
index 00000000000..20b9afe80cd
--- /dev/null
+++ b/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.stderr
@@ -0,0 +1,23 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/do-not-ice-on-invalid-lifetime.rs:3:12
+   |
+LL |     x: Vec<A> = Vec::new(),
+   |            ^ expected named lifetime parameter
+   |
+help: consider using the `'a` lifetime
+   |
+LL |     x: Vec<A<'a>> = Vec::new(),
+   |             ++++
+
+error[E0392]: lifetime parameter `'a` is never used
+  --> $DIR/do-not-ice-on-invalid-lifetime.rs:2:10
+   |
+LL | struct A<'a> {
+   |          ^^ unused lifetime parameter
+   |
+   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0106, E0392.
+For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/traits/const-traits/predicate-entailment-passes.rs b/tests/ui/traits/const-traits/predicate-entailment-passes.rs
index 9c8d5a5e3f6..28ae21891f3 100644
--- a/tests/ui/traits/const-traits/predicate-entailment-passes.rs
+++ b/tests/ui/traits/const-traits/predicate-entailment-passes.rs
@@ -6,32 +6,21 @@
 #[const_trait] trait Bar {}
 impl const Bar for () {}
 
-
 #[const_trait] trait TildeConst {
-    type Bar<T> where T: ~const Bar;
-
     fn foo<T>() where T: ~const Bar;
 }
 impl TildeConst for () {
-    type Bar<T> = () where T: Bar;
-
     fn foo<T>() where T: Bar {}
 }
 
 
 #[const_trait] trait AlwaysConst {
-    type Bar<T> where T: const Bar;
-
     fn foo<T>() where T: const Bar;
 }
 impl AlwaysConst for i32 {
-    type Bar<T> = () where T: Bar;
-
     fn foo<T>() where T: Bar {}
 }
 impl const AlwaysConst for u32 {
-    type Bar<T> = () where T: ~const Bar;
-
     fn foo<T>() where T: ~const Bar {}
 }
 
diff --git a/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr
index 8bf8536c74e..4e324209fe9 100644
--- a/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr
+++ b/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr
@@ -1,4 +1,4 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements
+error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements
   --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:28
    |
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
@@ -24,4 +24,4 @@ LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0803`.
diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr
index 1d42dbdfe00..294fa0d7613 100644
--- a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr
+++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr
@@ -1,18 +1,8 @@
-error[E0275]: overflow evaluating the requirement `<T as Overflow>::Assoc: Sized`
+error[E0275]: overflow evaluating the requirement `<T as Overflow>::Assoc == _`
   --> $DIR/trait_ref_is_knowable-norm-overflow.rs:10:18
    |
 LL |     type Assoc = <T as Overflow>::Assoc;
    |                  ^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: required by a bound in `Overflow::Assoc`
-  --> $DIR/trait_ref_is_knowable-norm-overflow.rs:7:5
-   |
-LL |     type Assoc;
-   |     ^^^^^^^^^^^ required by this bound in `Overflow::Assoc`
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL |     type Assoc: ?Sized;
-   |               ++++++++
 
 error[E0119]: conflicting implementations of trait `Trait`
   --> $DIR/trait_ref_is_knowable-norm-overflow.rs:18:1
diff --git a/tests/ui/traits/next-solver/gat-wf.rs b/tests/ui/traits/next-solver/gat-wf.rs
new file mode 100644
index 00000000000..ff6e2665ef3
--- /dev/null
+++ b/tests/ui/traits/next-solver/gat-wf.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -Znext-solver
+
+// Make sure that, like the old trait solver, we end up requiring that the WC of
+// impl GAT matches that of the trait. This is not a restriction that we *need*,
+// but is a side-effect of registering the where clauses when normalizing the GAT
+// when proving it satisfies its item bounds.
+
+trait Foo {
+    type T<'a>: Sized where Self: 'a;
+}
+
+impl Foo for &() {
+    type T<'a> = (); //~ the type `&()` does not fulfill the required lifetime
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/gat-wf.stderr b/tests/ui/traits/next-solver/gat-wf.stderr
new file mode 100644
index 00000000000..620bca77e4b
--- /dev/null
+++ b/tests/ui/traits/next-solver/gat-wf.stderr
@@ -0,0 +1,15 @@
+error[E0477]: the type `&()` does not fulfill the required lifetime
+  --> $DIR/gat-wf.rs:13:18
+   |
+LL |     type T<'a> = ();
+   |                  ^^
+   |
+note: type must outlive the lifetime `'a` as defined here
+  --> $DIR/gat-wf.rs:13:12
+   |
+LL |     type T<'a> = ();
+   |            ^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0477`.
diff --git a/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr b/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr
index 04288112fa8..ae00d3fc667 100644
--- a/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr
+++ b/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr
@@ -15,7 +15,7 @@ note: but lifetime parameter must outlive the lifetime `'b` as defined here
 LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b;
    |                     ^^
 
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+error[E0803]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/closure_wf_outlives.rs:34:9
    |
 LL |         || {}
@@ -63,5 +63,5 @@ LL |     type Opaque<T: 'static> = impl Sized;
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0310, E0478, E0495.
+Some errors have detailed explanations: E0310, E0478, E0803.
 For more information about an error, try `rustc --explain E0310`.