about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock39
-rw-r--r--README.md39
-rw-r--r--RELEASES.md10
-rw-r--r--compiler/rustc_abi/src/lib.rs7
-rw-r--r--compiler/rustc_ast/src/ast.rs5
-rw-r--r--compiler/rustc_ast/src/ptr.rs16
-rw-r--r--compiler/rustc_ast/src/token.rs2
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs2
-rw-r--r--compiler/rustc_ast/src/util/parser.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs8
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs2
-rw-r--r--compiler/rustc_attr/Cargo.toml1
-rw-r--r--compiler/rustc_attr/src/builtin.rs19
-rw-r--r--compiler/rustc_borrowck/src/borrow_set.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs20
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs15
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/polonius.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs9
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs8
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl2
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/assert.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_accessible.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs40
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/edition_panic.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/env.rs51
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs15
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs24
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs24
-rw-r--r--compiler/rustc_codegen_cranelift/src/vtable.rs2
-rw-r--r--compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch4
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs120
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs50
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs35
-rw-r--r--compiler/rustc_codegen_ssa/src/common.rs41
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs32
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs46
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/consts.rs1
-rw-r--r--compiler/rustc_const_eval/messages.ftl1
-rw-r--r--compiler/rustc_const_eval/src/errors.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs17
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs18
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs4
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs13
-rw-r--r--compiler/rustc_const_eval/src/util/mod.rs4
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/mod.rs8
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs48
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/copy.rs1
-rw-r--r--compiler/rustc_errors/src/lib.rs37
-rw-r--r--compiler/rustc_expand/src/build.rs40
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs7
-rw-r--r--compiler/rustc_hir/src/hir_id.rs6
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl2
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs160
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs47
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs390
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs357
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs89
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl4
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs337
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs5
-rw-r--r--compiler/rustc_index/src/bit_set.rs2
-rw-r--r--compiler/rustc_index_macros/src/newtype.rs3
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/snapshot/fudge.rs6
-rw-r--r--compiler/rustc_infer/src/lib.rs2
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs2
-rw-r--r--compiler/rustc_interface/src/passes.rs3
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lint/src/lints.rs28
-rw-r--r--compiler/rustc_lint/src/types.rs96
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs12
-rw-r--r--compiler/rustc_llvm/build.rs6
-rw-r--r--compiler/rustc_log/Cargo.toml2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs16
-rw-r--r--compiler/rustc_middle/src/arena.rs1
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs5
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs8
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs2
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs3
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs9
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs10
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs4
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs17
-rw-r--r--compiler/rustc_middle/src/mir/query.rs65
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs4
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs20
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs10
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs6
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs4
-rw-r--r--compiler/rustc_middle/src/thir.rs8
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs2
-rw-r--r--compiler/rustc_middle/src/traits/select.rs52
-rw-r--r--compiler/rustc_middle/src/ty/cast.rs4
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs1
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs122
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs66
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs24
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/region.rs4
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs1
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs29
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs45
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs17
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs191
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs25
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs52
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs20
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs5
-rw-r--r--compiler/rustc_mir_build/src/errors.rs23
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs57
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs10
-rw-r--r--compiler/rustc_mir_transform/messages.ftl49
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs615
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs12
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs161
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs7
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs12
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs171
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs2
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs12
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs14
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs2
-rw-r--r--compiler/rustc_mir_transform/src/nrvo.rs7
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs3
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs4
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs8
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_enum_branching.rs (renamed from compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs)57
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs16
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs89
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs2
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs2
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs1
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs2
-rw-r--r--compiler/rustc_parse_format/src/lib.rs2
-rw-r--r--compiler/rustc_passes/src/entry.rs13
-rw-r--r--compiler/rustc_pattern_analysis/Cargo.toml2
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs40
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs49
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs49
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs2
-rw-r--r--compiler/rustc_resolve/src/ident.rs2
-rw-r--r--compiler/rustc_resolve/src/imports.rs6
-rw-r--r--compiler/rustc_session/messages.ftl2
-rw-r--r--compiler/rustc_session/src/config.rs39
-rw-r--r--compiler/rustc_session/src/errors.rs4
-rw-r--r--compiler/rustc_session/src/options.rs9
-rw-r--r--compiler/rustc_session/src/session.rs80
-rw-r--r--compiler/rustc_session/src/utils.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs5
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs5
-rw-r--r--compiler/rustc_span/src/def_id.rs2
-rw-r--r--compiler/rustc_span/src/hygiene.rs4
-rw-r--r--compiler/rustc_span/src/lib.rs12
-rw-r--r--compiler/rustc_span/src/source_map.rs15
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs12
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs12
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid.rs15
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs594
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs8
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs27
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs3
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs62
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs120
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs138
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs44
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs28
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs2
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs40
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs3
-rw-r--r--compiler/rustc_type_ir/src/fold.rs51
-rw-r--r--compiler/rustc_type_ir/src/interner.rs13
-rw-r--r--compiler/rustc_type_ir/src/lib.rs2
-rw-r--r--compiler/rustc_type_ir/src/new.rs2
-rw-r--r--compiler/stable_mir/src/mir/body.rs7
-rw-r--r--compiler/stable_mir/src/ty.rs4
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs8
-rw-r--r--library/alloc/src/lib.rs2
-rw-r--r--library/alloc/src/raw_vec.rs8
-rw-r--r--library/alloc/src/string.rs6
-rw-r--r--library/alloc/src/vec/mod.rs4
-rw-r--r--library/alloc/tests/lib.rs2
-rw-r--r--library/core/src/any.rs8
-rw-r--r--library/core/src/clone.rs3
-rw-r--r--library/core/src/cmp.rs43
-rw-r--r--library/core/src/default.rs4
-rw-r--r--library/core/src/fmt/mod.rs4
-rw-r--r--library/core/src/hash/mod.rs14
-rw-r--r--library/core/src/intrinsics.rs33
-rw-r--r--library/core/src/intrinsics/simd.rs13
-rw-r--r--library/core/src/lib.rs5
-rw-r--r--library/core/src/macros/mod.rs3
-rw-r--r--library/core/src/marker.rs13
-rw-r--r--library/core/src/num/error.rs3
-rw-r--r--library/core/src/num/int_macros.rs106
-rw-r--r--library/core/src/num/mod.rs304
-rw-r--r--library/core/src/num/nonzero.rs3
-rw-r--r--library/core/src/num/uint_macros.rs107
-rw-r--r--library/core/src/ptr/const_ptr.rs40
-rw-r--r--library/core/src/ptr/metadata.rs3
-rw-r--r--library/core/src/ptr/mod.rs48
-rw-r--r--library/core/src/ptr/mut_ptr.rs41
-rw-r--r--library/core/src/ptr/non_null.rs20
-rw-r--r--library/core/src/slice/index.rs11
-rw-r--r--library/core/src/slice/mod.rs8
-rw-r--r--library/core/src/sync/atomic.rs12
-rw-r--r--library/core/src/task/wake.rs67
-rw-r--r--library/core/tests/intrinsics.rs27
-rw-r--r--library/core/tests/lib.rs4
-rw-r--r--library/core/tests/num/mod.rs10
-rw-r--r--library/core/tests/ptr.rs10
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs18
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs18
-rw-r--r--library/portable-simd/crates/core_simd/tests/pointers.rs18
-rw-r--r--library/std/src/fs.rs4
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--library/std/src/os/xous/ffi.rs2
-rw-r--r--library/std/src/panic.rs3
-rw-r--r--library/std/src/panicking.rs3
-rw-r--r--library/std/src/rt.rs11
-rw-r--r--library/std/src/sys/pal/hermit/thread.rs14
-rw-r--r--library/std/src/sys/pal/itron/thread.rs14
-rw-r--r--library/std/src/sys/pal/mod.rs6
-rw-r--r--library/std/src/sys/pal/sgx/thread.rs10
-rw-r--r--library/std/src/sys/pal/teeos/thread.rs12
-rw-r--r--library/std/src/sys/pal/uefi/thread.rs10
-rw-r--r--library/std/src/sys/pal/unix/rand.rs20
-rw-r--r--library/std/src/sys/pal/unix/stack_overflow.rs312
-rw-r--r--library/std/src/sys/pal/unix/thread.rs341
-rw-r--r--library/std/src/sys/pal/unsupported/thread.rs10
-rw-r--r--library/std/src/sys/pal/wasi/thread.rs10
-rw-r--r--library/std/src/sys/pal/wasip2/cabi_realloc.rs65
-rw-r--r--library/std/src/sys/pal/wasip2/mod.rs8
-rw-r--r--library/std/src/sys/pal/windows/stack_overflow.rs30
-rw-r--r--library/std/src/sys/pal/windows/stack_overflow_uwp.rs9
-rw-r--r--library/std/src/sys/pal/windows/thread.rs16
-rw-r--r--library/std/src/sys/pal/xous/thread.rs10
-rw-r--r--library/std/src/sys/pal/xous/thread_local_key.rs2
-rw-r--r--library/std/src/sys/pal/zkvm/thread_local_key.rs4
-rw-r--r--library/std/src/sys/personality/dwarf/eh.rs2
-rw-r--r--library/std/src/sys/sync/rwlock/queue.rs6
-rw-r--r--library/std/src/sys_common/mod.rs1
-rw-r--r--library/std/src/sys_common/thread_info.rs53
-rw-r--r--library/std/src/thread/mod.rs32
-rw-r--r--src/bootstrap/src/bin/rustc.rs14
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs20
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs20
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs34
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs156
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs12
-rw-r--r--src/bootstrap/src/core/builder.rs148
-rw-r--r--src/bootstrap/src/core/builder/tests.rs2
-rw-r--r--src/bootstrap/src/core/config/flags.rs3
-rw-r--r--src/bootstrap/src/lib.rs2
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh1
-rwxr-xr-xsrc/ci/docker/run.sh1
-rwxr-xr-xsrc/ci/scripts/upload-artifacts.sh14
-rw-r--r--src/doc/rustc/src/codegen-options/index.md14
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustc/src/platform-support/netbsd.md8
-rw-r--r--src/doc/unstable-book/src/compiler-flags/external-clangrt.md6
-rw-r--r--src/doc/unstable-book/src/compiler-flags/remap-path-scope.md8
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md15
-rw-r--r--src/etc/completions/x.py.fish2
-rw-r--r--src/etc/completions/x.py.ps12
-rw-r--r--src/etc/completions/x.py.sh10
-rw-r--r--src/etc/completions/x.py.zsh2
-rw-r--r--src/etc/lldb_commands3
-rw-r--r--src/etc/lldb_lookup.py5
-rw-r--r--src/etc/lldb_providers.py29
-rw-r--r--src/etc/rust_types.py6
-rw-r--r--src/librustdoc/Cargo.toml4
-rw-r--r--src/librustdoc/clean/auto_trait.rs1030
-rw-r--r--src/librustdoc/clean/mod.rs109
-rw-r--r--src/librustdoc/clean/simplify.rs45
-rw-r--r--src/librustdoc/clean/types.rs7
-rw-r--r--src/librustdoc/clean/utils.rs16
-rw-r--r--src/librustdoc/html/render/mod.rs35
-rw-r--r--src/librustdoc/html/render/search_index.rs107
-rw-r--r--src/librustdoc/html/render/search_index/encode.rs243
-rw-r--r--src/librustdoc/html/render/write_shared.rs31
-rw-r--r--src/librustdoc/html/static/.eslintrc.js2
-rw-r--r--src/librustdoc/html/static/js/main.js32
-rw-r--r--src/librustdoc/html/static/js/search.js509
-rw-r--r--src/librustdoc/html/static/js/storage.js4
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/compiletest/src/lib.rs4
-rw-r--r--src/tools/miri/Cargo.toml1
-rw-r--r--src/tools/miri/README.md2
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs88
-rw-r--r--src/tools/miri/cargo-miri/src/setup.rs6
-rw-r--r--src/tools/miri/cargo-miri/src/util.rs7
-rwxr-xr-xsrc/tools/miri/ci/ci.sh25
-rw-r--r--src/tools/miri/miri-script/src/commands.rs23
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs6
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs10
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs8
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs14
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs42
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs4
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs2
-rw-r--r--src/tools/miri/src/concurrency/thread.rs2
-rw-r--r--src/tools/miri/src/diagnostics.rs8
-rw-r--r--src/tools/miri/src/shims/intrinsics/simd.rs10
-rw-r--r--src/tools/miri/test-cargo-miri/Cargo.lock90
-rw-r--r--src/tools/miri/test-cargo-miri/Cargo.toml12
-rw-r--r--src/tools/miri/test-cargo-miri/issue-1760/Cargo.toml8
-rw-r--r--src/tools/miri/test-cargo-miri/proc-macro-crate/Cargo.toml13
-rw-r--r--src/tools/miri/test-cargo-miri/proc-macro-crate/build.rs (renamed from src/tools/miri/test-cargo-miri/issue-1760/build.rs)0
-rw-r--r--src/tools/miri/test-cargo-miri/proc-macro-crate/src/lib.rs (renamed from src/tools/miri/test-cargo-miri/issue-1760/src/lib.rs)0
-rw-r--r--src/tools/miri/test-cargo-miri/src/lib.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/unchecked_add1.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/unchecked_add2.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/unchecked_mul1.rs1
-rw-r--r--src/tools/miri/tests/fail/intrinsics/unchecked_mul2.rs1
-rw-r--r--src/tools/miri/tests/fail/intrinsics/unchecked_sub1.rs1
-rw-r--r--src/tools/miri/tests/fail/intrinsics/unchecked_sub2.rs1
-rw-r--r--src/tools/miri/tests/fail/provenance/ptr_int_unexposed.rs2
-rw-r--r--src/tools/miri/tests/fail/provenance/ptr_invalid.rs2
-rw-r--r--src/tools/miri/tests/fail/provenance/strict_provenance_cast.rs2
-rw-r--r--src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr6
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs4
-rw-r--r--src/tools/miri/tests/pass-dep/shims/posix_memalign.rs2
-rw-r--r--src/tools/miri/tests/pass/async-closure-captures.rs91
-rw-r--r--src/tools/miri/tests/pass/async-closure-captures.stdout10
-rw-r--r--src/tools/miri/tests/pass/box.stack.stderr6
-rw-r--r--src/tools/miri/tests/pass/extern_types.stack.stderr6
-rw-r--r--src/tools/miri/tests/pass/portable-simd-ptrs.rs4
-rw-r--r--src/tools/miri/tests/pass/ptr_int_from_exposed.rs18
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs6
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr6
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs2
-rw-r--r--src/tools/miri/tests/ui.rs57
-rw-r--r--src/tools/run-make-support/src/lib.rs6
-rw-r--r--src/tools/run-make-support/src/rustc.rs32
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml4
-rw-r--r--src/tools/rust-analyzer/.github/workflows/publish-libs.yaml1
-rw-r--r--src/tools/rust-analyzer/.github/workflows/release.yaml17
-rw-r--r--src/tools/rust-analyzer/Cargo.lock43
-rw-r--r--src/tools/rust-analyzer/Cargo.toml11
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs84
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs80
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs85
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs165
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs65
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs38
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/builder.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs84
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs82
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs159
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs39
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs95
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs239
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs56
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs65
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs15
-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/display_source_code.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs109
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs166
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs60
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs49
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs47
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs50
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs23
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs28
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/file_structure.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs71
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs175
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs96
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs28
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/status.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs48
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html83
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html15
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html57
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html11
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs76
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/test_explorer.rs68
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing.rs33
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/benchmark.rs20
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander.rs45
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs160
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs99
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/lib.rs64
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/parser.rs100
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs56
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs6
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs14
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs58
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0034_match_arms_recovery.rast113
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0034_match_arms_recovery.rs11
-rw-r--r--src/tools/rust-analyzer/crates/paths/Cargo.toml6
-rw-r--r--src/tools/rust-analyzer/crates/paths/src/lib.rs242
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs12
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs47
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs26
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs16
-rw-r--r--src/tools/rust-analyzer/crates/project-model/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs19
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs21
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/project_json.rs20
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs6
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs20
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs86
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs49
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs18
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs31
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs3
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs107
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs36
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs92
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs13
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs22
-rw-r--r--src/tools/rust-analyzer/crates/span/src/lib.rs50
-rw-r--r--src/tools/rust-analyzer/crates/syntax/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs3378
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs80
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/tests.rs25
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs25
-rw-r--r--src/tools/rust-analyzer/crates/toolchain/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/toolchain/src/lib.rs43
-rw-r--r--src/tools/rust-analyzer/crates/tt/Cargo.toml5
-rw-r--r--src/tools/rust-analyzer/crates/tt/src/lib.rs11
-rw-r--r--src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/lib.rs57
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/loader.rs2
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs2
-rw-r--r--src/tools/rust-analyzer/docs/dev/lsp-extensions.md14
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc5
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json9
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts25
-rw-r--r--src/tools/rust-analyzer/editors/code/src/debug.ts6
-rw-r--r--src/tools/rust-analyzer/editors/code/src/lsp_ext.ts6
-rw-r--r--src/tools/rust-analyzer/editors/code/src/run.ts28
-rw-r--r--src/tools/rust-analyzer/editors/code/src/tasks.ts50
-rw-r--r--src/tools/rust-analyzer/editors/code/src/test_explorer.ts63
-rw-r--r--src/tools/rust-analyzer/xtask/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/xtask/src/codegen.rs2
-rw-r--r--src/tools/rust-analyzer/xtask/src/codegen/grammar.rs (renamed from src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs)72
-rw-r--r--src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs (renamed from src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs)0
-rw-r--r--src/tools/rust-analyzer/xtask/src/dist.rs21
-rw-r--r--src/tools/rust-analyzer/xtask/src/flags.rs141
-rw-r--r--src/tools/rust-analyzer/xtask/src/install.rs16
-rw-r--r--src/tools/rust-installer/src/tarballer.rs12
-rw-r--r--src/tools/rustdoc-js/.eslintrc.js2
-rw-r--r--src/tools/rustdoc-js/tester.js99
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt2
-rw-r--r--src/tools/tidy/src/issues.txt19
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/assembly/is_aligned.rs2
-rw-r--r--tests/assembly/x86_64-cmp.rs51
-rw-r--r--tests/auxiliary/rust_test_helpers.c24
-rw-r--r--tests/codegen/cast-target-abi.rs280
-rw-r--r--tests/codegen/cffi/ffi-out-of-bounds-loads.rs28
-rw-r--r--tests/codegen/enum/uninhabited_enum_default_branch.rs24
-rw-r--r--tests/codegen/enum/unreachable_enum_default_branch.rs43
-rw-r--r--tests/codegen/intrinsics/three_way_compare.rs47
-rw-r--r--tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs4
-rw-r--r--tests/codegen/unchecked_shifts.rs49
-rw-r--r--tests/codegen/vec_pop_push_noop.rs6
-rw-r--r--tests/debuginfo/path.rs29
-rw-r--r--tests/incremental/hashes/function_interfaces.rs8
-rw-r--r--tests/incremental/hashes/inherent_impls.rs8
-rw-r--r--tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir2
-rw-r--r--tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir2
-rw-r--r--tests/mir-opt/box_expr.main.ElaborateDrops.diff2
-rw-r--r--tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir8
-rw-r--r--tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir2
-rw-r--r--tests/mir-opt/building/match/deref-patterns/string.foo.PreCodegen.after.mir (renamed from tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir)0
-rw-r--r--tests/mir-opt/building/match/deref-patterns/string.rs (renamed from tests/mir-opt/deref-patterns/string.rs)0
-rw-r--r--tests/mir-opt/building/match/exponential_or.match_tuple.SimplifyCfg-initial.after.mir (renamed from tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir)0
-rw-r--r--tests/mir-opt/building/match/exponential_or.rs (renamed from tests/mir-opt/exponential_or.rs)0
-rw-r--r--tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir (renamed from tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir)0
-rw-r--r--tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir (renamed from tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir)0
-rw-r--r--tests/mir-opt/building/match/match_false_edges.main.built.after.mir (renamed from tests/mir-opt/building/match_false_edges.main.built.after.mir)2
-rw-r--r--tests/mir-opt/building/match/match_false_edges.rs (renamed from tests/mir-opt/building/match_false_edges.rs)0
-rw-r--r--tests/mir-opt/building/match/simple_match.match_bool.built.after.mir (renamed from tests/mir-opt/building/simple_match.match_bool.built.after.mir)0
-rw-r--r--tests/mir-opt/building/match/simple_match.rs (renamed from tests/mir-opt/building/simple_match.rs)0
-rw-r--r--tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir118
-rw-r--r--tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir88
-rw-r--r--tests/mir-opt/building/match/sort_candidates.rs41
-rw-r--r--tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir6
-rw-r--r--tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir6
-rw-r--r--tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff2
-rw-r--r--tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff2
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff2
-rw-r--r--tests/mir-opt/const_prop/invalid_constant.main.GVN.diff12
-rw-r--r--tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff12
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff2
-rw-r--r--tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff)2
-rw-r--r--tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff)2
-rw-r--r--tests/mir-opt/const_prop/pointer_expose_provenance.rs (renamed from tests/mir-opt/const_prop/pointer_expose_address.rs)4
-rw-r--r--tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff4
-rw-r--r--tests/mir-opt/const_prop/reify_fn_ptr.rs4
-rw-r--r--tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff2
-rw-r--r--tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-abort.diff4
-rw-r--r--tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-abort.diff4
-rw-r--r--tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff38
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff38
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff38
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff38
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff38
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff38
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff38
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff38
-rw-r--r--tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff8
-rw-r--r--tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff8
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff2
-rw-r--r--tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff4
-rw-r--r--tests/mir-opt/dead-store-elimination/provenance_soundness.rs4
-rw-r--r--tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff6
-rw-r--r--tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff6
-rw-r--r--tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff10
-rw-r--r--tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff10
-rw-r--r--tests/mir-opt/gvn.slices.GVN.panic-abort.diff6
-rw-r--r--tests/mir-opt/gvn.slices.GVN.panic-unwind.diff6
-rw-r--r--tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff12
-rw-r--r--tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff12
-rw-r--r--tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff6
-rw-r--r--tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff6
-rw-r--r--tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff4
-rw-r--r--tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff4
-rw-r--r--tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff8
-rw-r--r--tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff8
-rw-r--r--tests/mir-opt/inline/inline_instruction_set.default.Inline.diff2
-rw-r--r--tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff20
-rw-r--r--tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff12
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.rs19
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff36
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff36
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir22
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir22
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff13
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff13
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir13
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir13
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff8
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff8
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir8
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir8
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff41
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff41
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir27
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir27
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff14
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff14
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir10
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir10
-rw-r--r--tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff24
-rw-r--r--tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff24
-rw-r--r--tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify.diff28
-rw-r--r--tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-abort.mir2
-rw-r--r--tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir8
-rw-r--r--tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir8
-rw-r--r--tests/mir-opt/issue_72181.main.built.after.mir2
-rw-r--r--tests/mir-opt/issue_72181_1.main.built.after.mir2
-rw-r--r--tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff6
-rw-r--r--tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-abort.diff2
-rw-r--r--tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.rs21
-rw-r--r--tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-abort.diff34
-rw-r--r--tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff34
-rw-r--r--tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-abort.diff31
-rw-r--r--tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff31
-rw-r--r--tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-abort.diff34
-rw-r--r--tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff34
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff183
-rw-r--r--tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff183
-rw-r--r--tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff8
-rw-r--r--tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff8
-rw-r--r--tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir106
-rw-r--r--tests/mir-opt/match_test.rs19
-rw-r--r--tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir10
-rw-r--r--tests/mir-opt/pre-codegen/derived_ord.rs9
-rw-r--r--tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir78
-rw-r--r--tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir6
-rw-r--r--tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir4
-rw-r--r--tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-abort.mir20
-rw-r--r--tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-unwind.mir20
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir4
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir4
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir4
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir4
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir48
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir48
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir44
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir44
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir4
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir4
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir50
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir50
-rw-r--r--tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff2
-rw-r--r--tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff258
-rw-r--r--tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff232
-rw-r--r--tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff4
-rw-r--r--tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-abort.mir10
-rw-r--r--tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-unwind.mir10
-rw-r--r--tests/mir-opt/simplify_dead_blocks.assert_nonzero_nonmax.SimplifyCfg-after-unreachable-enum-branching.diff33
-rw-r--r--tests/mir-opt/simplify_dead_blocks.rs52
-rw-r--r--tests/mir-opt/simplify_duplicate_unreachable_blocks.assert_nonzero_nonmax.SimplifyCfg-after-uninhabited-enum-branching.diff25
-rw-r--r--tests/mir-opt/simplify_duplicate_unreachable_blocks.rs31
-rw-r--r--tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff (renamed from tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff)8
-rw-r--r--tests/mir-opt/simplify_locals.rs6
-rw-r--r--tests/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff2
-rw-r--r--tests/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff2
-rw-r--r--tests/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff2
-rw-r--r--tests/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff2
-rw-r--r--tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff2
-rw-r--r--tests/mir-opt/tls_access.main.PreCodegen.after.mir6
-rw-r--r--tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir2
-rw-r--r--tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir2
-rw-r--r--tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff (renamed from tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff)4
-rw-r--r--tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff (renamed from tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff)4
-rw-r--r--tests/mir-opt/uninhabited_fallthrough_elimination.rs4
-rw-r--r--tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir2
-rw-r--r--tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-abort.diff (renamed from tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-unwind.diff (renamed from tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-abort.diff (renamed from tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-unwind.diff (renamed from tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-abort.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-unwind.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-abort.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-unwind.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-abort.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-abort.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-unwind.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-abort.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-unwind.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-abort.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff)6
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-unwind.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff)6
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-abort.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff)6
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-unwind.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-unwind.diff)6
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-abort.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff)6
-rw-r--r--tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-unwind.diff (renamed from tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff)6
-rw-r--r--tests/mir-opt/unreachable_enum_branching.rs (renamed from tests/mir-opt/uninhabited_enum_branching.rs)40
-rw-r--r--tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff (renamed from tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-abort.diff)4
-rw-r--r--tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff (renamed from tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff)4
-rw-r--r--tests/run-make/core-no-fp-fmt-parse/Makefile4
-rw-r--r--tests/run-make/core-no-fp-fmt-parse/rmake.rs17
-rw-r--r--tests/run-make/hir-tree/Makefile8
-rw-r--r--tests/run-make/hir-tree/input.rs3
-rw-r--r--tests/run-make/non-unicode-env/non_unicode_env.rs3
-rw-r--r--tests/run-make/non-unicode-env/non_unicode_env.stderr10
-rw-r--r--tests/run-make/non-unicode-env/rmake.rs14
-rw-r--r--tests/run-make/remap-path-prefix/Makefile13
-rw-r--r--tests/run-make/split-debuginfo/Makefile4
-rw-r--r--tests/rustdoc-gui/anchors.goml2
-rw-r--r--tests/rustdoc-gui/code-color.goml2
-rw-r--r--tests/rustdoc-gui/codeblock-tooltip.goml2
-rw-r--r--tests/rustdoc-gui/cursor.goml2
-rw-r--r--tests/rustdoc-gui/docblock-code-block-line-number.goml2
-rw-r--r--tests/rustdoc-gui/docblock-table.goml2
-rw-r--r--tests/rustdoc-gui/escape-key.goml2
-rw-r--r--tests/rustdoc-gui/globals.goml2
-rw-r--r--tests/rustdoc-gui/go-to-collapsed-elem.goml4
-rw-r--r--tests/rustdoc-gui/headers-color.goml2
-rw-r--r--tests/rustdoc-gui/headings-anchor.goml8
-rw-r--r--tests/rustdoc-gui/headings.goml10
-rw-r--r--tests/rustdoc-gui/help-page.goml8
-rw-r--r--tests/rustdoc-gui/highlight-colors.goml4
-rw-r--r--tests/rustdoc-gui/item-decl-colors.goml4
-rw-r--r--tests/rustdoc-gui/item-decl-comment-highlighting.goml4
-rw-r--r--tests/rustdoc-gui/item-info-alignment.goml4
-rw-r--r--tests/rustdoc-gui/item-info.goml4
-rw-r--r--tests/rustdoc-gui/jump-to-def-background.goml17
-rw-r--r--tests/rustdoc-gui/label-next-to-symbol.goml12
-rw-r--r--tests/rustdoc-gui/links-color.goml4
-rw-r--r--tests/rustdoc-gui/notable-trait.goml20
-rw-r--r--tests/rustdoc-gui/pocket-menu.goml2
-rw-r--r--tests/rustdoc-gui/run-on-hover.goml2
-rw-r--r--tests/rustdoc-gui/rust-logo.goml2
-rw-r--r--tests/rustdoc-gui/scrape-examples-color.goml6
-rw-r--r--tests/rustdoc-gui/scrape-examples-toggle.goml2
-rw-r--r--tests/rustdoc-gui/search-corrections.goml10
-rw-r--r--tests/rustdoc-gui/search-error.goml2
-rw-r--r--tests/rustdoc-gui/search-filter.goml2
-rw-r--r--tests/rustdoc-gui/search-form-elements.goml4
-rw-r--r--tests/rustdoc-gui/search-keyboard.goml2
-rw-r--r--tests/rustdoc-gui/search-no-result.goml2
-rw-r--r--tests/rustdoc-gui/search-reexport.goml4
-rw-r--r--tests/rustdoc-gui/search-result-color.goml246
-rw-r--r--tests/rustdoc-gui/search-result-display.goml4
-rw-r--r--tests/rustdoc-gui/search-result-impl-disambiguation.goml4
-rw-r--r--tests/rustdoc-gui/search-result-keyword.goml2
-rw-r--r--tests/rustdoc-gui/search-tab-change-title-fn-sig.goml10
-rw-r--r--tests/rustdoc-gui/search-tab.goml12
-rw-r--r--tests/rustdoc-gui/setting-auto-hide-content-large-items.goml2
-rw-r--r--tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml2
-rw-r--r--tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml2
-rw-r--r--tests/rustdoc-gui/setting-go-to-only-result.goml4
-rw-r--r--tests/rustdoc-gui/settings.goml2
-rw-r--r--tests/rustdoc-gui/sidebar-links-color.goml4
-rw-r--r--tests/rustdoc-gui/sidebar-mobile.goml2
-rw-r--r--tests/rustdoc-gui/sidebar-source-code-display.goml4
-rw-r--r--tests/rustdoc-gui/sidebar-source-code.goml2
-rw-r--r--tests/rustdoc-gui/sidebar.goml2
-rw-r--r--tests/rustdoc-gui/source-code-page.goml6
-rw-r--r--tests/rustdoc-gui/stab-badge.goml2
-rw-r--r--tests/rustdoc-gui/target.goml2
-rw-r--r--tests/rustdoc-gui/toggle-docs.goml2
-rw-r--r--tests/rustdoc-gui/type-declation-overflow.goml8
-rw-r--r--tests/rustdoc-gui/unsafe-fn.goml17
-rw-r--r--tests/rustdoc-gui/warning-block.goml2
-rw-r--r--tests/rustdoc-gui/where-whitespace.goml10
-rw-r--r--tests/rustdoc-ui/synthetic-auto-trait-impls/const-in-super-trait-and-item-bound.rs23
-rw-r--r--tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl-normalize.rs17
-rw-r--r--tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl.rs11
-rw-r--r--tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.rs18
-rw-r--r--tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr25
-rw-r--r--tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.rs10
-rw-r--r--tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr9
-rw-r--r--tests/rustdoc/search-index-summaries.rs2
-rw-r--r--tests/rustdoc/synthetic_auto/bounds.rs21
-rw-r--r--tests/rustdoc/synthetic_auto/complex.rs4
-rw-r--r--tests/rustdoc/synthetic_auto/lifetimes.rs2
-rw-r--r--tests/rustdoc/synthetic_auto/no-redundancy.rs5
-rw-r--r--tests/rustdoc/synthetic_auto/project.rs6
-rw-r--r--tests/ui-fulldeps/stable-mir/check_normalization.rs95
-rw-r--r--tests/ui/abi/extern/extern-pass-FiveU16s.rs30
-rw-r--r--tests/ui/abi/extern/extern-return-FiveU16s.rs26
-rw-r--r--tests/ui/asm/x86_64/goto.rs2
-rw-r--r--tests/ui/asm/x86_64/goto.stderr (renamed from tests/ui/asm/x86_64/goto.mirunsafeck.stderr)4
-rw-r--r--tests/ui/asm/x86_64/goto.thirunsafeck.stderr23
-rw-r--r--tests/ui/async-await/async-closures/captures.rs82
-rw-r--r--tests/ui/async-await/async-closures/captures.run.stdout10
-rw-r--r--tests/ui/async-await/async-is-unwindsafe.rs1
-rw-r--r--tests/ui/async-await/async-is-unwindsafe.stderr43
-rw-r--r--tests/ui/async-await/coroutine-desc.stderr28
-rw-r--r--tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs34
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs56
-rw-r--r--tests/ui/binop/binary-op-suggest-deref.stderr6
-rw-r--r--tests/ui/closures/issue-1460.rs (renamed from tests/ui/issues/issue-1460.rs)0
-rw-r--r--tests/ui/closures/issue-1460.stderr (renamed from tests/ui/issues/issue-1460.stderr)0
-rw-r--r--tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr10
-rw-r--r--tests/ui/coherence/negative-coherence/regions-in-canonical.rs23
-rw-r--r--tests/ui/coherence/negative-coherence/regions-in-canonical.stderr11
-rw-r--r--tests/ui/compiletest-self-test/test-aux-bin.rs2
-rw-r--r--tests/ui/consts/const-eval/parse_ints.rs10
-rw-r--r--tests/ui/consts/const-eval/parse_ints.stderr31
-rw-r--r--tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr19
-rw-r--r--tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr19
-rw-r--r--tests/ui/consts/const-int-unchecked.rs14
-rw-r--r--tests/ui/consts/const-int-unchecked.stderr24
-rw-r--r--tests/ui/derives/auxiliary/rustc-serialize.rs16
-rw-r--r--tests/ui/derives/rustc-decodable-issue-123156.rs11
-rw-r--r--tests/ui/derives/rustc-decodable-issue-123156.stderr10
-rw-r--r--tests/ui/feature-gates/feature-gate-f128.e2015.stderr (renamed from tests/ui/feature-gates/feature-gate-f128.stderr)10
-rw-r--r--tests/ui/feature-gates/feature-gate-f128.e2018.stderr53
-rw-r--r--tests/ui/feature-gates/feature-gate-f128.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-f16.e2015.stderr (renamed from tests/ui/feature-gates/feature-gate-f16.stderr)10
-rw-r--r--tests/ui/feature-gates/feature-gate-f16.e2018.stderr53
-rw-r--r--tests/ui/feature-gates/feature-gate-f16.rs4
-rw-r--r--tests/ui/fn/fn-item-lifetime-bounds.rs37
-rw-r--r--tests/ui/fn/fn-item-type.stderr50
-rw-r--r--tests/ui/fn/issue-1451.rs (renamed from tests/ui/issues/issue-1451.rs)0
-rw-r--r--tests/ui/fn/issue-1900.rs (renamed from tests/ui/issues/issue-1900.rs)0
-rw-r--r--tests/ui/fn/issue-1900.stderr (renamed from tests/ui/issues/issue-1900.stderr)0
-rw-r--r--tests/ui/higher-ranked/builtin-closure-like-bounds.rs58
-rw-r--r--tests/ui/higher-ranked/closure-bound-codegen-ice.rs33
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs28
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr26
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr25
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr19
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr26
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs20
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr54
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr67
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs62
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-1.rs (renamed from tests/ui/higher-ranked/leak-check-in-selection.rs)0
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr23
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr23
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs18
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr35
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr48
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs39
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs29
-rw-r--r--tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr19
-rw-r--r--tests/ui/higher-ranked/trait-bounds/fn-ptr.current.stderr19
-rw-r--r--tests/ui/higher-ranked/trait-bounds/fn-ptr.rs3
-rw-r--r--tests/ui/higher-ranked/trait-bounds/future.classic.stderr6
-rw-r--r--tests/ui/higher-ranked/trait-bounds/future.current.stderr6
-rw-r--r--tests/ui/higher-ranked/trait-bounds/future.rs9
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.rs (renamed from tests/ui/higher-ranked/trait-bounds/issue-30786.rs)20
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr27
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs116
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr27
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr22
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs32
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr86
-rw-r--r--tests/ui/higher-ranked/trait-bounds/issue-30786.stderr51
-rw-r--r--tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs1
-rw-r--r--tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr19
-rw-r--r--tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs11
-rw-r--r--tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr27
-rw-r--r--tests/ui/implied-bounds/issue-100690.rs11
-rw-r--r--tests/ui/implied-bounds/issue-100690.stderr49
-rw-r--r--tests/ui/issues/issue-1476.rs3
-rw-r--r--tests/ui/issues/issue-1476.stderr9
-rw-r--r--tests/ui/issues/issue-1696.rs8
-rw-r--r--tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs79
-rw-r--r--tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr106
-rw-r--r--tests/ui/lifetimes/issue-105675.rs2
-rw-r--r--tests/ui/lifetimes/lifetime-errors/issue_74400.rs4
-rw-r--r--tests/ui/lint/lint-strict-provenance-fuzzy-casts.stderr2
-rw-r--r--tests/ui/lint/lint-strict-provenance-lossy-casts.stderr8
-rw-r--r--tests/ui/lint/wide_pointer_comparisons.rs36
-rw-r--r--tests/ui/lint/wide_pointer_comparisons.stderr291
-rw-r--r--tests/ui/loops/issue-1962.fixed (renamed from tests/ui/issues/issue-1962.fixed)0
-rw-r--r--tests/ui/loops/issue-1962.rs (renamed from tests/ui/issues/issue-1962.rs)0
-rw-r--r--tests/ui/loops/issue-1962.stderr (renamed from tests/ui/issues/issue-1962.stderr)0
-rw-r--r--tests/ui/loops/issue-1974.rs (renamed from tests/ui/issues/issue-1974.rs)0
-rw-r--r--tests/ui/marker_trait_attr/unsound-overlap.rs1
-rw-r--r--tests/ui/marker_trait_attr/unsound-overlap.stderr21
-rw-r--r--tests/ui/match/postfix-match/match-after-as.rs7
-rw-r--r--tests/ui/match/postfix-match/match-after-as.stderr28
-rw-r--r--tests/ui/methods/probe-overflow-due-to-sized-predicate-ordering.rs30
-rw-r--r--tests/ui/mir/alignment/packed.rs2
-rw-r--r--tests/ui/mismatched_types/binops.stderr12
-rw-r--r--tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs14
-rw-r--r--tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr97
-rw-r--r--tests/ui/mismatched_types/issue-1362.rs (renamed from tests/ui/issues/issue-1362.rs)0
-rw-r--r--tests/ui/mismatched_types/issue-1362.stderr (renamed from tests/ui/issues/issue-1362.stderr)0
-rw-r--r--tests/ui/mismatched_types/issue-1448-2.rs (renamed from tests/ui/issues/issue-1448-2.rs)0
-rw-r--r--tests/ui/mismatched_types/issue-1448-2.stderr (renamed from tests/ui/issues/issue-1448-2.stderr)0
-rw-r--r--tests/ui/nll/match-cfg-fake-edges.rs97
-rw-r--r--tests/ui/nll/match-cfg-fake-edges.stderr158
-rw-r--r--tests/ui/nll/match-cfg-fake-edges2.rs21
-rw-r--r--tests/ui/nll/match-cfg-fake-edges2.stderr4
-rw-r--r--tests/ui/pattern/usefulness/unions.rs35
-rw-r--r--tests/ui/pattern/usefulness/unions.stderr34
-rw-r--r--tests/ui/proc-macro/bad-projection.rs1
-rw-r--r--tests/ui/proc-macro/bad-projection.stderr14
-rw-r--r--tests/ui/repr/repr-align.rs8
-rw-r--r--tests/ui/repr/repr-align.stderr42
-rw-r--r--tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs19
-rw-r--r--tests/ui/resolve/primitive-f16-f128-shadowed.rs3
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr23
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr23
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr115
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr115
-rw-r--r--tests/ui/sanitizer/cfg.rs1
-rw-r--r--tests/ui/sanitizer/cfi-async-closures.rs33
-rw-r--r--tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs22
-rw-r--r--tests/ui/sanitizer/cfi-closures.rs79
-rw-r--r--tests/ui/sanitizer/cfi-complex-receiver.rs1
-rw-r--r--tests/ui/sanitizer/cfi-coroutine.rs67
-rw-r--r--tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs42
-rw-r--r--tests/ui/sanitizer/cfi-self-ref.rs1
-rw-r--r--tests/ui/sanitizer/cfi-supertraits.rs73
-rw-r--r--tests/ui/sanitizer/cfi-virtual-auto.rs1
-rw-r--r--tests/ui/simd/intrinsic/ptr-cast.rs10
-rw-r--r--tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs7
-rw-r--r--tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr36
-rw-r--r--tests/ui/specialization/issue-39448.rs3
-rw-r--r--tests/ui/specialization/issue-39448.stderr31
-rw-r--r--tests/ui/specialization/issue-39618.rs3
-rw-r--r--tests/ui/specialization/issue-39618.stderr20
-rw-r--r--tests/ui/stability-attribute/stability-in-private-module.rs4
-rw-r--r--tests/ui/stability-attribute/stability-in-private-module.stderr16
-rw-r--r--tests/ui/static/issue-1660.rs (renamed from tests/ui/issues/issue-1660.rs)0
-rw-r--r--tests/ui/statics/nested-allocations-dont-inherit-codegen-attrs.rs11
-rw-r--r--tests/ui/statics/nested_thread_local.rs14
-rw-r--r--tests/ui/statics/nested_thread_local.stderr8
-rw-r--r--tests/ui/structs-enums/type-sizes.rs2
-rw-r--r--tests/ui/traits/stack-error-order-dependence-2.rs24
-rw-r--r--tests/ui/traits/stack-error-order-dependence.rs19
-rw-r--r--tests/ui/unpretty/hir-tree.rs10
-rw-r--r--tests/ui/wf/wf-fn-def-check-sig-1.rs44
-rw-r--r--tests/ui/wf/wf-fn-def-check-sig-1.stderr15
-rw-r--r--tests/ui/wf/wf-fn-def-check-sig-2.rs44
-rw-r--r--tests/ui/wf/wf-fn-def-check-sig-2.stderr15
-rw-r--r--triagebot.toml1
1139 files changed, 17988 insertions, 12576 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c4501d6e574..d5c9a5e4d0d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2591,6 +2591,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "nu-ansi-term"
+version = "0.49.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68"
+dependencies = [
+ "windows-sys 0.48.0",
+]
+
+[[package]]
 name = "num-conv"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3560,6 +3569,7 @@ dependencies = [
 name = "rustc_attr"
 version = "0.0.0"
 dependencies = [
+ "rustc_abi",
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_data_structures",
@@ -4773,6 +4783,8 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "askama",
+ "base64",
+ "byteorder",
  "expect-test",
  "indexmap",
  "itertools 0.12.1",
@@ -5358,9 +5370,9 @@ dependencies = [
 
 [[package]]
 name = "sysinfo"
-version = "0.30.7"
+version = "0.30.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c385888ef380a852a16209afc8cfad22795dd8873d69c9a14d2e2088f118d18"
+checksum = "4b1a378e48fb3ce3a5cf04359c456c9c98ff689bcf1c1bc6e6a31f247686f275"
 dependencies = [
  "cfg-if",
  "core-foundation-sys",
@@ -5780,17 +5792,6 @@ dependencies = [
 
 [[package]]
 name = "tracing-log"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2"
-dependencies = [
- "log",
- "once_cell",
- "tracing-core",
-]
-
-[[package]]
-name = "tracing-log"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
@@ -5807,7 +5808,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
 dependencies = [
  "matchers",
- "nu-ansi-term",
+ "nu-ansi-term 0.46.0",
  "once_cell",
  "parking_lot",
  "regex",
@@ -5816,18 +5817,18 @@ dependencies = [
  "thread_local",
  "tracing",
  "tracing-core",
- "tracing-log 0.2.0",
+ "tracing-log",
 ]
 
 [[package]]
 name = "tracing-tree"
-version = "0.2.5"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ec6adcab41b1391b08a308cc6302b79f8095d1673f6947c2dc65ffb028b0b2d"
+checksum = "65139ecd2c3f6484c3b99bc01c77afe21e95473630747c7aca525e78b0666675"
 dependencies = [
- "nu-ansi-term",
+ "nu-ansi-term 0.49.0",
  "tracing-core",
- "tracing-log 0.1.4",
+ "tracing-log",
  "tracing-subscriber",
 ]
 
diff --git a/README.md b/README.md
index 6d6383351ca..3690a9c93c5 100644
--- a/README.md
+++ b/README.md
@@ -1,27 +1,36 @@
-# The Rust Programming Language
-
-[![Rust Community](https://img.shields.io/badge/Rust_Community%20-Join_us-brightgreen?style=plastic&logo=rust)](https://www.rust-lang.org/community)
+<div align="center">
+  <picture>
+    <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rust-lang/www.rust-lang.org/master/static/images/rust-social-wide-dark.svg">
+    <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/rust-lang/www.rust-lang.org/master/static/images/rust-social-wide-light.svg">
+    <img alt="The Rust Programming Language: A language empowering everyone to build reliable and efficient software"
+         src="https://raw.githubusercontent.com/rust-lang/www.rust-lang.org/master/static/images/rust-social-wide-light.svg"
+         width="50%">
+  </picture>
+
+[Website][Rust] | [Getting started] | [Learn] | [Documentation] | [Contributing]
+</div>
 
 This is the main source code repository for [Rust]. It contains the compiler,
 standard library, and documentation.
 
 [Rust]: https://www.rust-lang.org/
+[Getting Started]: https://www.rust-lang.org/learn/get-started
+[Learn]: https://www.rust-lang.org/learn
+[Documentation]: https://www.rust-lang.org/learn#learn-use
+[Contributing]: CONTRIBUTING.md
+
+## Why Rust?
 
-**Note: this README is for _users_ rather than _contributors_.**
-If you wish to _contribute_ to the compiler, you should read
-[CONTRIBUTING.md](CONTRIBUTING.md) instead.
+- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrate with other languages.
 
-<details>
-<summary>Table of Contents</summary>
+- **Reliability:** Our rich type system and ownership model ensure memory and thread safety, reducing bugs at compile-time.
 
-- [Quick Start](#quick-start)
-- [Installing from Source](#installing-from-source)
-- [Getting Help](#getting-help)
-- [Contributing](#contributing)
-- [License](#license)
-- [Trademark](#trademark)
+- **Productivity:** Comprehensive documentation, a compiler committed to providing great diagnostics, and advanced tooling including package manager and build tool ([Cargo]), auto-formatter ([rustfmt]), linter ([Clippy]) and editor support ([rust-analyzer]).
 
-</details>
+[Cargo]: https://github.com/rust-lang/cargo
+[rustfmt]: https://github.com/rust-lang/rustfmt
+[Clippy]: https://github.com/rust-lang/rust-clippy
+[rust-analyzer]: https://github.com/rust-lang/rust-analyzer
 
 ## Quick Start
 
diff --git a/RELEASES.md b/RELEASES.md
index 922afdd3e18..f35dd27ec24 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,13 @@
+Version 1.77.1 (2024-03-28)
+===========================
+
+<a id="1.77.1"></a>
+
+- [Revert stripping debuginfo by default for Windows](https://github.com/rust-lang/cargo/pull/13654)
+  This fixes a regression in 1.77 by reverting to the previous default.
+  Platforms other than Windows are not affected.
+- Internal: [Fix heading anchor rendering in doc pages](https://github.com/rust-lang/rust/pull/122693)
+
 Version 1.77.0 (2024-03-21)
 ==========================
 
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 4f2b9d0ef50..7439af7aed3 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -698,6 +698,7 @@ impl fmt::Display for AlignFromBytesError {
 
 impl Align {
     pub const ONE: Align = Align { pow2: 0 };
+    pub const EIGHT: Align = Align { pow2: 3 };
     // LLVM has a maximal supported alignment of 2^29, we inherit that.
     pub const MAX: Align = Align { pow2: 29 };
 
@@ -707,19 +708,19 @@ impl Align {
     }
 
     #[inline]
-    pub fn from_bytes(align: u64) -> Result<Align, AlignFromBytesError> {
+    pub const fn from_bytes(align: u64) -> Result<Align, AlignFromBytesError> {
         // Treat an alignment of 0 bytes like 1-byte alignment.
         if align == 0 {
             return Ok(Align::ONE);
         }
 
         #[cold]
-        fn not_power_of_2(align: u64) -> AlignFromBytesError {
+        const fn not_power_of_2(align: u64) -> AlignFromBytesError {
             AlignFromBytesError::NotPowerOfTwo(align)
         }
 
         #[cold]
-        fn too_large(align: u64) -> AlignFromBytesError {
+        const fn too_large(align: u64) -> AlignFromBytesError {
             AlignFromBytesError::TooLarge(align)
         }
 
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 46f052da3eb..e29ef591bcb 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1276,7 +1276,8 @@ impl Expr {
             ExprKind::While(..) => ExprPrecedence::While,
             ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
             ExprKind::Loop(..) => ExprPrecedence::Loop,
-            ExprKind::Match(..) => ExprPrecedence::Match,
+            ExprKind::Match(_, _, MatchKind::Prefix) => ExprPrecedence::Match,
+            ExprKind::Match(_, _, MatchKind::Postfix) => ExprPrecedence::PostfixMatch,
             ExprKind::Closure(..) => ExprPrecedence::Closure,
             ExprKind::Block(..) => ExprPrecedence::Block,
             ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
@@ -3349,7 +3350,7 @@ impl TryFrom<ItemKind> for ForeignItemKind {
 pub type ForeignItem = Item<ForeignItemKind>;
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index 0140fb752bf..e22a523dbc3 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -1,6 +1,6 @@
 //! The AST pointer.
 //!
-//! Provides `P<T>`, a frozen owned smart pointer.
+//! Provides [`P<T>`][struct@P], an owned smart pointer.
 //!
 //! # Motivations and benefits
 //!
@@ -8,18 +8,14 @@
 //!   passes (e.g., one may be able to bypass the borrow checker with a shared
 //!   `ExprKind::AddrOf` node taking a mutable borrow).
 //!
-//! * **Immutability**: `P<T>` disallows mutating its inner `T`, unlike `Box<T>`
-//!   (unless it contains an `Unsafe` interior, but that may be denied later).
-//!   This mainly prevents mistakes, but also enforces a kind of "purity".
-//!
 //! * **Efficiency**: folding can reuse allocation space for `P<T>` and `Vec<T>`,
 //!   the latter even when the input and output types differ (as it would be the
 //!   case with arenas or a GADT AST using type parameters to toggle features).
 //!
-//! * **Maintainability**: `P<T>` provides a fixed interface - `Deref`,
-//!   `and_then` and `map` - which can remain fully functional even if the
-//!   implementation changes (using a special thread-local heap, for example).
-//!   Moreover, a switch to, e.g., `P<'a, T>` would be easy and mostly automated.
+//! * **Maintainability**: `P<T>` provides an interface, which can remain fully
+//!   functional even if the implementation changes (using a special thread-local
+//!   heap, for example). Moreover, a switch to, e.g., `P<'a, T>` would be easy
+//!   and mostly automated.
 
 use std::fmt::{self, Debug, Display};
 use std::ops::{Deref, DerefMut};
@@ -29,6 +25,8 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 /// An owned smart pointer.
+///
+/// See the [module level documentation][crate::ptr] for details.
 pub struct P<T: ?Sized> {
     ptr: Box<T>,
 }
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index f49eb2f22c5..5060bbec421 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -1021,7 +1021,7 @@ where
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 239735456ad..f3249f3e5a8 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -768,7 +768,7 @@ impl DelimSpacing {
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 13768c12017..373c0ebcc5c 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -281,6 +281,7 @@ pub enum ExprPrecedence {
     ForLoop,
     Loop,
     Match,
+    PostfixMatch,
     ConstBlock,
     Block,
     TryBlock,
@@ -334,7 +335,8 @@ impl ExprPrecedence {
             | ExprPrecedence::InlineAsm
             | ExprPrecedence::Mac
             | ExprPrecedence::FormatArgs
-            | ExprPrecedence::OffsetOf => PREC_POSTFIX,
+            | ExprPrecedence::OffsetOf
+            | ExprPrecedence::PostfixMatch => PREC_POSTFIX,
 
             // Never need parens
             ExprPrecedence::Array
@@ -390,7 +392,8 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
         | ast::ExprKind::Cast(x, _)
         | ast::ExprKind::Type(x, _)
         | ast::ExprKind::Field(x, _)
-        | ast::ExprKind::Index(x, _, _) => {
+        | ast::ExprKind::Index(x, _, _)
+        | ast::ExprKind::Match(x, _, ast::MatchKind::Postfix) => {
             // &X { y: 1 }, X { y: 1 }.y
             contains_exterior_struct_lit(x)
         }
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index a1164008d0d..402044c7af9 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -3,7 +3,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::*;
-use rustc_index::{Idx, IndexVec};
+use rustc_index::IndexVec;
 use rustc_middle::span_bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::{Span, DUMMY_SP};
@@ -31,7 +31,7 @@ pub(super) fn index_hir<'hir>(
     bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>,
     num_nodes: usize,
 ) -> (IndexVec<ItemLocalId, ParentedNode<'hir>>, LocalDefIdMap<ItemLocalId>) {
-    let zero_id = ItemLocalId::new(0);
+    let zero_id = ItemLocalId::ZERO;
     let err_node = ParentedNode { parent: zero_id, node: Node::Err(item.span()) };
     let mut nodes = IndexVec::from_elem_n(err_node, num_nodes);
     // This node's parent should never be accessed: the owner's parent is computed by the
@@ -112,7 +112,9 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
     }
 
     fn insert_nested(&mut self, item: LocalDefId) {
-        self.parenting.insert(item, self.parent_node);
+        if self.parent_node.as_u32() != 0 {
+            self.parenting.insert(item, self.parent_node);
+        }
     }
 }
 
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index c9786328565..abfea6078f2 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -11,7 +11,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::PredicateOrigin;
-use rustc_index::{Idx, IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::span_bug;
 use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
 use rustc_span::edit_distance::find_best_match_for_name;
@@ -563,7 +563,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         let kind =
                             this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs);
                         if let Some(attrs) = attrs {
-                            this.attrs.insert(hir::ItemLocalId::new(0), attrs);
+                            this.attrs.insert(hir::ItemLocalId::ZERO, attrs);
                         }
 
                         let item = hir::Item {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 833b0e9b567..8cf347bfa96 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -157,7 +157,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             attrs: SortedMap::default(),
             children: Vec::default(),
             current_hir_id_owner: hir::CRATE_OWNER_ID,
-            item_local_id_counter: hir::ItemLocalId::new(0),
+            item_local_id_counter: hir::ItemLocalId::ZERO,
             node_id_to_local_id: Default::default(),
             trait_map: Default::default(),
 
@@ -583,7 +583,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s.
 
         // Always allocate the first `HirId` for the owner itself.
-        let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::new(0));
+        let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO);
         debug_assert_eq!(_old, None);
 
         let item = f(self);
@@ -677,7 +677,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 v.insert(local_id);
                 self.item_local_id_counter.increment_by(1);
 
-                assert_ne!(local_id, hir::ItemLocalId::new(0));
+                assert_ne!(local_id, hir::ItemLocalId::ZERO);
                 if let Some(def_id) = self.opt_local_def_id(ast_node_id) {
                     self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
                 }
@@ -696,7 +696,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn next_id(&mut self) -> hir::HirId {
         let owner = self.current_hir_id_owner;
         let local_id = self.item_local_id_counter;
-        assert_ne!(local_id, hir::ItemLocalId::new(0));
+        assert_ne!(local_id, hir::ItemLocalId::ZERO);
         self.item_local_id_counter.increment_by(1);
         hir::HirId { owner, local_id }
     }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 96a10447393..093a985495c 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1571,7 +1571,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
 /// like it's setting an associated type, provide an appropriate suggestion.
 fn deny_equality_constraints(
-    this: &mut AstValidator<'_>,
+    this: &AstValidator<'_>,
     predicate: &WhereEqPredicate,
     generics: &Generics,
 ) {
diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml
index d33416d2003..3b24452450a 100644
--- a/compiler/rustc_attr/Cargo.toml
+++ b/compiler/rustc_attr/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
+rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 814104ec78c..439f13e7635 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -1,5 +1,6 @@
 //! Parsing and validation of builtin attributes
 
+use rustc_abi::Align;
 use rustc_ast::{self as ast, attr};
 use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId};
 use rustc_ast_pretty::pprust;
@@ -919,10 +920,10 @@ pub enum ReprAttr {
     ReprInt(IntType),
     ReprRust,
     ReprC,
-    ReprPacked(u32),
+    ReprPacked(Align),
     ReprSimd,
     ReprTransparent,
-    ReprAlign(u32),
+    ReprAlign(Align),
 }
 
 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
@@ -968,7 +969,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                 let hint = match item.name_or_empty() {
                     sym::Rust => Some(ReprRust),
                     sym::C => Some(ReprC),
-                    sym::packed => Some(ReprPacked(1)),
+                    sym::packed => Some(ReprPacked(Align::ONE)),
                     sym::simd => Some(ReprSimd),
                     sym::transparent => Some(ReprTransparent),
                     sym::align => {
@@ -1209,11 +1210,17 @@ fn allow_unstable<'a>(
     })
 }
 
-pub fn parse_alignment(node: &ast::LitKind) -> Result<u32, &'static str> {
+pub fn parse_alignment(node: &ast::LitKind) -> Result<Align, &'static str> {
     if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
+        // `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first
         if literal.get().is_power_of_two() {
-            // rustc_middle::ty::layout::Align restricts align to <= 2^29
-            if *literal <= 1 << 29 { Ok(literal.get() as u32) } else { Err("larger than 2^29") }
+            // Only possible error is larger than 2^29
+            literal
+                .get()
+                .try_into()
+                .ok()
+                .and_then(|v| Align::from_bytes(v).ok())
+                .ok_or("larger than 2^29")
         } else {
             Err("not a power of two")
         }
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index 6a683d129de..a38dd286be5 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -159,7 +159,7 @@ impl<'tcx> BorrowSet<'tcx> {
     }
 
     pub(crate) fn indices(&self) -> impl Iterator<Item = BorrowIndex> {
-        BorrowIndex::from_usize(0)..BorrowIndex::from_usize(self.len())
+        BorrowIndex::ZERO..BorrowIndex::from_usize(self.len())
     }
 
     pub(crate) fn iter_enumerated(&self) -> impl Iterator<Item = (BorrowIndex, &BorrowData<'tcx>)> {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 578369de4d6..62e16d445c6 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -337,7 +337,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     fn suggest_ref_or_clone(
-        &mut self,
+        &self,
         mpi: MovePathIndex,
         move_span: Span,
         err: &mut Diag<'tcx>,
@@ -1125,7 +1125,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     pub(crate) fn report_use_while_mutably_borrowed(
-        &mut self,
+        &self,
         location: Location,
         (place, _span): (Place<'tcx>, Span),
         borrow: &BorrowData<'tcx>,
@@ -1174,7 +1174,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     pub(crate) fn report_conflicting_borrow(
-        &mut self,
+        &self,
         location: Location,
         (place, span): (Place<'tcx>, Span),
         gen_borrow_kind: BorrowKind,
@@ -2463,7 +2463,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     fn report_local_value_does_not_live_long_enough(
-        &mut self,
+        &self,
         location: Location,
         name: &str,
         borrow: &BorrowData<'tcx>,
@@ -2642,7 +2642,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     fn report_thread_local_value_does_not_live_long_enough(
-        &mut self,
+        &self,
         drop_span: Span,
         borrow_span: Span,
     ) -> Diag<'tcx> {
@@ -2663,7 +2663,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     #[instrument(level = "debug", skip(self))]
     fn report_temporary_value_does_not_live_long_enough(
-        &mut self,
+        &self,
         location: Location,
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
@@ -2921,7 +2921,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     #[instrument(level = "debug", skip(self))]
     fn report_escaping_closure_capture(
-        &mut self,
+        &self,
         use_span: UseSpans<'tcx>,
         var_span: Span,
         fr_name: &RegionName,
@@ -3031,7 +3031,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     fn report_escaping_data(
-        &mut self,
+        &self,
         borrow_span: Span,
         name: &Option<String>,
         upvar_span: Span,
@@ -3065,7 +3065,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     fn get_moved_indexes(
-        &mut self,
+        &self,
         location: Location,
         mpi: MovePathIndex,
     ) -> (Vec<MoveSite>, Vec<Location>) {
@@ -3854,7 +3854,7 @@ enum AnnotatedBorrowFnSignature<'tcx> {
 impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
     /// Annotate the provided diagnostic with information about borrow from the fn signature that
     /// helps explain.
-    pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diag<'_>) -> String {
+    pub(crate) fn emit(&self, cx: &MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diag<'_>) -> String {
         match self {
             &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
                 diag.span_label(
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 26bb6800348..bd068b29c12 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -540,19 +540,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         }
     }
 
+    /// Suggest `map[k] = v` => `map.insert(k, v)` and the like.
     fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diag<'tcx>, span: Span) {
         let Some(adt) = ty.ty_adt_def() else { return };
         let did = adt.did();
         if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
             || self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
         {
-            struct V<'a, 'tcx> {
+            /// Walks through the HIR, looking for the corresponding span for this error.
+            /// When it finds it, see if it corresponds to assignment operator whose LHS
+            /// is an index expr.
+            struct SuggestIndexOperatorAlternativeVisitor<'a, 'tcx> {
                 assign_span: Span,
                 err: &'a mut Diag<'tcx>,
                 ty: Ty<'tcx>,
                 suggested: bool,
             }
-            impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
+            impl<'a, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'tcx> {
                 fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
                     hir::intravisit::walk_stmt(self, stmt);
                     let expr = match stmt.kind {
@@ -645,7 +649,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) else { return };
             let body = self.infcx.tcx.hir().body(body_id);
 
-            let mut v = V { assign_span: span, err, ty, suggested: false };
+            let mut v = SuggestIndexOperatorAlternativeVisitor {
+                assign_span: span,
+                err,
+                ty,
+                suggested: false,
+            };
             v.visit_body(body);
             if !v.suggested {
                 err.help(format!(
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index 45f7b07fd5f..7f530227043 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -87,6 +87,8 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
     body: &Body<'tcx>,
     location_table: &LocationTable,
     move_data: &MoveData<'tcx>,
+    //FIXME: this is not mutated, but expected to be modified as
+    // out param, bug?
     dropped_at: &mut Vec<(Local, Location)>,
 ) {
     debug!("populate_access_facts()");
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 18975a4e3b2..8bdefdfc0ac 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -200,7 +200,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
         for local in boring_locals {
             let local_ty = self.cx.body.local_decls[local].ty;
             let drop_data = self.cx.drop_data.entry(local_ty).or_insert_with({
-                let typeck = &mut self.cx.typeck;
+                let typeck = &self.cx.typeck;
                 move || LivenessContext::compute_drop_data(typeck, local_ty)
             });
 
@@ -542,7 +542,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
         );
 
         let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
-            let typeck = &mut self.typeck;
+            let typeck = &self.typeck;
             move || Self::compute_drop_data(typeck, dropped_ty)
         });
 
@@ -597,10 +597,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
         });
     }
 
-    fn compute_drop_data(
-        typeck: &mut TypeChecker<'_, 'tcx>,
-        dropped_ty: Ty<'tcx>,
-    ) -> DropData<'tcx> {
+    fn compute_drop_data(typeck: &TypeChecker<'_, 'tcx>, dropped_ty: Ty<'tcx>) -> DropData<'tcx> {
         debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
 
         match typeck
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index b0bdf4af097..71b54a761a2 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2261,7 +2261,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
 
-                    CastKind::PointerExposeAddress => {
+                    CastKind::PointerExposeProvenance => {
                         let ty_from = op.ty(body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
@@ -2271,7 +2271,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                 span_mirbug!(
                                     self,
                                     rvalue,
-                                    "Invalid PointerExposeAddress cast {:?} -> {:?}",
+                                    "Invalid PointerExposeProvenance cast {:?} -> {:?}",
                                     ty_from,
                                     ty
                                 )
@@ -2279,7 +2279,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
 
-                    CastKind::PointerFromExposedAddress => {
+                    CastKind::PointerWithExposedProvenance => {
                         let ty_from = op.ty(body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
@@ -2289,7 +2289,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                 span_mirbug!(
                                     self,
                                     rvalue,
-                                    "Invalid PointerFromExposedAddress cast {:?} -> {:?}",
+                                    "Invalid PointerWithExposedProvenance cast {:?} -> {:?}",
                                     ty_from,
                                     ty
                                 )
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index ba8401393d7..2a5bc58af3b 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -114,6 +114,8 @@ builtin_macros_env_not_defined = environment variable `{$var}` not defined at co
     .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
     .custom = use `std::env::var({$var_expr})` to read the variable at run time
 
+builtin_macros_env_not_unicode = environment variable `{$var}` is not a valid Unicode string
+
 builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
 
 builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 76805617c93..137ac441579 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -29,7 +29,7 @@ pub struct AsmArgs {
 }
 
 fn parse_args<'a>(
-    ecx: &mut ExtCtxt<'a>,
+    ecx: &ExtCtxt<'a>,
     sp: Span,
     tts: TokenStream,
     is_global_asm: bool,
@@ -303,7 +303,7 @@ pub fn parse_asm_args<'a>(
 ///
 /// This function must be called immediately after the option token is parsed.
 /// Otherwise, the suggestion will be incorrect.
-fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) {
+fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
     // Tool-only output
     let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span };
     p.psess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
@@ -315,7 +315,7 @@ fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) {
 /// This function must be called immediately after the option token is parsed.
 /// Otherwise, the error will not point to the correct spot.
 fn try_set_option<'a>(
-    p: &mut Parser<'a>,
+    p: &Parser<'a>,
     args: &mut AsmArgs,
     symbol: Symbol,
     option: ast::InlineAsmOptions,
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 5905bdd7108..d200179f3a0 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -111,7 +111,7 @@ fn expr_if_not(
     cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els)
 }
 
-fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
+fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
     let mut parser = cx.new_parser_from_tts(stream);
 
     if parser.token == token::Eof {
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index 9197b9ebdf9..5dc9bbacd06 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -35,7 +35,7 @@ pub fn expand_cfg(
     })
 }
 
-fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
+fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
     let mut p = cx.new_parser_from_tts(tts);
 
     if p.token == token::Eof {
diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
index 1933b2e1fb7..98c0ca3a526 100644
--- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
@@ -10,7 +10,7 @@ use rustc_span::Span;
 
 pub(crate) struct Expander;
 
-fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
+fn validate_input<'a>(ecx: &ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
     use errors::CfgAccessibleInvalid::*;
     match mi.meta_item_list() {
         None => {}
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index a2f827c5567..45fec294578 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -8,7 +8,7 @@ use crate::errors;
 
 /// Emits errors for literal expressions that are invalid inside and outside of an array.
 fn invalid_type_err(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     token_lit: token::Lit,
     span: Span,
     is_nested: bool,
@@ -65,7 +65,7 @@ fn invalid_type_err(
 /// Otherwise, returns `None`, and either pushes the `expr`'s span to `missing_literals` or
 /// updates `guar` accordingly.
 fn handle_array_element(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     guar: &mut Option<ErrorGuaranteed>,
     missing_literals: &mut Vec<rustc_span::Span>,
     expr: &P<rustc_ast::Expr>,
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
index 8027ca2e7bb..26ef3da3a91 100644
--- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
@@ -6,7 +6,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::Span;
 
 pub fn expand_deriving_copy(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -29,7 +29,7 @@ pub fn expand_deriving_copy(
 }
 
 pub fn expand_deriving_const_param_ty(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 267405ac32e..0a44bd42b91 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -9,7 +9,7 @@ use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
 pub fn expand_deriving_clone(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -94,7 +94,7 @@ pub fn expand_deriving_clone(
 
 fn cs_clone_simple(
     name: &str,
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
     is_union: bool,
@@ -157,14 +157,14 @@ fn cs_clone_simple(
 
 fn cs_clone(
     name: &str,
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
 ) -> BlockOrExpr {
     let ctor_path;
     let all_fields;
     let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]);
-    let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo| {
+    let subcall = |cx: &ExtCtxt<'_>, field: &FieldInfo| {
         let args = thin_vec![field.self_expr.clone()];
         cx.expr_call_global(field.span, fn_path.clone(), args)
     };
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index ce3fa1ab32c..45c4467a109 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -10,7 +10,7 @@ use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
 pub fn expand_deriving_eq(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -49,7 +49,7 @@ pub fn expand_deriving_eq(
 }
 
 fn cs_total_eq_assert(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
 ) -> BlockOrExpr {
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index 0923acfeedd..1d7a69540ab 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -8,7 +8,7 @@ use rustc_span::Span;
 use thin_vec::thin_vec;
 
 pub fn expand_deriving_ord(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -39,7 +39,7 @@ pub fn expand_deriving_ord(
     trait_def.expand(cx, mitem, item, push)
 }
 
-pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
+pub fn cs_cmp(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
     let test_id = Ident::new(sym::cmp, span);
     let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
     let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index 006110cd4b1..234918ae429 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -9,14 +9,14 @@ use rustc_span::Span;
 use thin_vec::thin_vec;
 
 pub fn expand_deriving_partial_eq(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
     is_const: bool,
 ) {
-    fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
+    fn cs_eq(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
         let base = true;
         let expr = cs_fold(
             true, // use foldl
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 60dbdf8b544..49fe89b18b0 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -8,7 +8,7 @@ use rustc_span::Span;
 use thin_vec::thin_vec;
 
 pub fn expand_deriving_partial_ord(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -69,7 +69,7 @@ pub fn expand_deriving_partial_ord(
 }
 
 fn cs_partial_cmp(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     substr: &Substructure<'_>,
     tag_then_data: bool,
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 03acd7f489f..e442b3520b2 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -9,7 +9,7 @@ use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
 pub fn expand_deriving_debug(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -45,7 +45,7 @@ pub fn expand_deriving_debug(
     trait_def.expand(cx, mitem, item, push)
 }
 
-fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
+fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
     // We want to make sure we have the ctxt set so that we can use unstable methods
     let span = cx.with_def_site_ctxt(span);
 
@@ -209,7 +209,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
 /// }
 /// ```
 fn show_fieldless_enum(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     def: &EnumDef,
     substr: &Substructure<'_>,
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index bf4693cd541..34798ab0a17 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -11,7 +11,7 @@ use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
 pub fn expand_deriving_rustc_decodable(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -63,7 +63,7 @@ pub fn expand_deriving_rustc_decodable(
 }
 
 fn decodable_substructure(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
     krate: Symbol,
@@ -186,14 +186,14 @@ fn decodable_substructure(
 /// - `outer_pat_path` is the path to this enum variant/struct
 /// - `getarg` should retrieve the `usize`-th field with name `@str`.
 fn decode_static_fields<F>(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     outer_pat_path: ast::Path,
     fields: &StaticFields,
     mut getarg: F,
 ) -> P<Expr>
 where
-    F: FnMut(&mut ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>,
+    F: FnMut(&ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>,
 {
     match fields {
         Unnamed(fields, is_tuple) => {
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 292a916e2a7..328770ce10d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -13,7 +13,7 @@ use smallvec::SmallVec;
 use thin_vec::{thin_vec, ThinVec};
 
 pub fn expand_deriving_default(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &ast::MetaItem,
     item: &Annotatable,
@@ -54,7 +54,7 @@ pub fn expand_deriving_default(
 }
 
 fn default_struct_substructure(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
     summary: &StaticFields,
@@ -81,7 +81,7 @@ fn default_struct_substructure(
 }
 
 fn default_enum_substructure(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     enum_def: &EnumDef,
 ) -> BlockOrExpr {
@@ -103,7 +103,7 @@ fn default_enum_substructure(
 }
 
 fn extract_default_variant<'a>(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     enum_def: &'a EnumDef,
     trait_span: Span,
 ) -> Result<&'a rustc_ast::Variant, ErrorGuaranteed> {
@@ -173,7 +173,7 @@ fn extract_default_variant<'a>(
 }
 
 fn validate_default_attribute(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     default_variant: &rustc_ast::Variant,
 ) -> Result<(), ErrorGuaranteed> {
     let attrs: SmallVec<[_; 1]> =
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index d939f8c7aeb..2e5f1173825 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -95,7 +95,7 @@ use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
 pub fn expand_deriving_rustc_encodable(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -147,7 +147,7 @@ pub fn expand_deriving_rustc_encodable(
 }
 
 fn encodable_substructure(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
     krate: Symbol,
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index afa73b672da..e16d74eed4e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -330,7 +330,7 @@ pub enum SubstructureFields<'a> {
 /// Combine the values of all the fields together. The last argument is
 /// all the fields of all the structures.
 pub type CombineSubstructureFunc<'a> =
-    Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>;
+    Box<dyn FnMut(&ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>;
 
 pub fn combine_substructure(
     f: CombineSubstructureFunc<'_>,
@@ -454,7 +454,7 @@ fn find_type_parameters(
 impl<'a> TraitDef<'a> {
     pub fn expand(
         self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         mitem: &ast::MetaItem,
         item: &'a Annotatable,
         push: &mut dyn FnMut(Annotatable),
@@ -464,7 +464,7 @@ impl<'a> TraitDef<'a> {
 
     pub fn expand_ext(
         self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         mitem: &ast::MetaItem,
         item: &'a Annotatable,
         push: &mut dyn FnMut(Annotatable),
@@ -577,7 +577,7 @@ impl<'a> TraitDef<'a> {
     /// therefore does not get bound by the derived trait.
     fn create_derived_impl(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         type_ident: Ident,
         generics: &Generics,
         field_tys: Vec<P<ast::Ty>>,
@@ -802,7 +802,7 @@ impl<'a> TraitDef<'a> {
 
     fn expand_struct_def(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         struct_def: &'a VariantData,
         type_ident: Ident,
         generics: &Generics,
@@ -856,7 +856,7 @@ impl<'a> TraitDef<'a> {
 
     fn expand_enum_def(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         enum_def: &'a EnumDef,
         type_ident: Ident,
         generics: &Generics,
@@ -914,7 +914,7 @@ impl<'a> TraitDef<'a> {
 impl<'a> MethodDef<'a> {
     fn call_substructure_method(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         type_ident: Ident,
         nonselflike_args: &[P<Expr>],
@@ -929,7 +929,7 @@ impl<'a> MethodDef<'a> {
 
     fn get_ret_ty(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         generics: &Generics,
         type_ident: Ident,
@@ -950,7 +950,7 @@ impl<'a> MethodDef<'a> {
     //   `&self`.
     fn extract_arg_details(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         type_ident: Ident,
         generics: &Generics,
@@ -986,7 +986,7 @@ impl<'a> MethodDef<'a> {
 
     fn create_method(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         type_ident: Ident,
         generics: &Generics,
@@ -1077,7 +1077,7 @@ impl<'a> MethodDef<'a> {
     /// ```
     fn expand_struct_method_body<'b>(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'b>,
         struct_def: &'b VariantData,
         type_ident: Ident,
@@ -1100,7 +1100,7 @@ impl<'a> MethodDef<'a> {
 
     fn expand_static_struct_method_body(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         struct_def: &VariantData,
         type_ident: Ident,
@@ -1154,7 +1154,7 @@ impl<'a> MethodDef<'a> {
     /// `Unify`), and possibly a default arm.
     fn expand_enum_method_body<'b>(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'b>,
         enum_def: &'b EnumDef,
         type_ident: Ident,
@@ -1403,7 +1403,7 @@ impl<'a> MethodDef<'a> {
 
     fn expand_static_enum_method_body(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         enum_def: &EnumDef,
         type_ident: Ident,
@@ -1430,7 +1430,7 @@ impl<'a> MethodDef<'a> {
 
 // general helper methods.
 impl<'a> TraitDef<'a> {
-    fn summarise_struct(&self, cx: &mut ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields {
+    fn summarise_struct(&self, cx: &ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields {
         let mut named_idents = Vec::new();
         let mut just_spans = Vec::new();
         for field in struct_def.fields() {
@@ -1460,7 +1460,7 @@ impl<'a> TraitDef<'a> {
 
     fn create_struct_patterns(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         struct_path: ast::Path,
         struct_def: &'a VariantData,
         prefixes: &[String],
@@ -1553,7 +1553,7 @@ impl<'a> TraitDef<'a> {
 
     fn create_struct_pattern_fields(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         struct_def: &'a VariantData,
         prefixes: &[String],
     ) -> Vec<FieldInfo> {
@@ -1570,7 +1570,7 @@ impl<'a> TraitDef<'a> {
 
     fn create_struct_field_access_fields(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         selflike_args: &[P<Expr>],
         struct_def: &'a VariantData,
         is_packed: bool,
@@ -1668,13 +1668,13 @@ pub enum CsFold<'a> {
 /// Statics may not be folded over.
 pub fn cs_fold<F>(
     use_foldl: bool,
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substructure: &Substructure<'_>,
     mut f: F,
 ) -> P<Expr>
 where
-    F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
+    F: FnMut(&ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
 {
     match substructure.fields {
         EnumMatching(.., all_fields) | Struct(_, all_fields) => {
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index dd6149cf614..6bb61311bd2 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -8,7 +8,7 @@ use rustc_span::Span;
 use thin_vec::thin_vec;
 
 pub fn expand_deriving_hash(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -46,11 +46,7 @@ pub fn expand_deriving_hash(
     hash_trait_def.expand(cx, mitem, item, push);
 }
 
-fn hash_substructure(
-    cx: &mut ExtCtxt<'_>,
-    trait_span: Span,
-    substr: &Substructure<'_>,
-) -> BlockOrExpr {
+fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
     let [state_expr] = substr.nonselflike_args else {
         cx.dcx().span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
     };
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index 8a3375cba9d..9f786d22c93 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -40,7 +40,7 @@ pub mod partial_ord;
 pub mod generic;
 
 pub(crate) type BuiltinDeriveFn =
-    fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool);
+    fn(&ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool);
 
 pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn);
 
@@ -117,7 +117,7 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
 }
 
 fn assert_ty_bounds(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     stmts: &mut ThinVec<ast::Stmt>,
     ty: P<ast::Ty>,
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs
index fa22e911642..bb3c83e8c0e 100644
--- a/compiler/rustc_builtin_macros/src/edition_panic.rs
+++ b/compiler/rustc_builtin_macros/src/edition_panic.rs
@@ -40,7 +40,7 @@ pub fn expand_unreachable<'cx>(
 
 fn expand<'cx>(
     mac: rustc_span::Symbol,
-    cx: &'cx mut ExtCtxt<'_>,
+    cx: &'cx ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
 ) -> MacroExpanderResult<'cx> {
diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs
index bce710e5cab..93873045943 100644
--- a/compiler/rustc_builtin_macros/src/env.rs
+++ b/compiler/rustc_builtin_macros/src/env.rs
@@ -11,18 +11,19 @@ use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpa
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use std::env;
+use std::env::VarError;
 use thin_vec::thin_vec;
 
 use crate::errors;
 
-fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Option<Symbol> {
+fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result<Symbol, VarError> {
     let var = var.as_str();
     if let Some(value) = cx.sess.opts.logical_env.get(var) {
-        return Some(Symbol::intern(value));
+        return Ok(Symbol::intern(value));
     }
     // If the environment variable was not defined with the `--env-set` option, we try to retrieve it
     // from rustc's environment.
-    env::var(var).ok().as_deref().map(Symbol::intern)
+    Ok(Symbol::intern(&env::var(var)?))
 }
 
 pub fn expand_option_env<'cx>(
@@ -39,7 +40,7 @@ pub fn expand_option_env<'cx>(
     };
 
     let sp = cx.with_def_site_ctxt(sp);
-    let value = lookup_env(cx, var);
+    let value = lookup_env(cx, var).ok();
     cx.sess.psess.env_depinfo.borrow_mut().insert((var, value));
     let e = match value {
         None => {
@@ -108,9 +109,9 @@ pub fn expand_env<'cx>(
 
     let span = cx.with_def_site_ctxt(sp);
     let value = lookup_env(cx, var);
-    cx.sess.psess.env_depinfo.borrow_mut().insert((var, value));
+    cx.sess.psess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied()));
     let e = match value {
-        None => {
+        Err(err) => {
             let ExprKind::Lit(token::Lit {
                 kind: LitKind::Str | LitKind::StrRaw(..), symbol, ..
             }) = &var_expr.kind
@@ -118,25 +119,33 @@ pub fn expand_env<'cx>(
                 unreachable!("`expr_to_string` ensures this is a string lit")
             };
 
-            let guar = if let Some(msg_from_user) = custom_msg {
-                cx.dcx().emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user })
-            } else if is_cargo_env_var(var.as_str()) {
-                cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar {
-                    span,
-                    var: *symbol,
-                    var_expr: var_expr.ast_deref(),
-                })
-            } else {
-                cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar {
-                    span,
-                    var: *symbol,
-                    var_expr: var_expr.ast_deref(),
-                })
+            let guar = match err {
+                VarError::NotPresent => {
+                    if let Some(msg_from_user) = custom_msg {
+                        cx.dcx()
+                            .emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user })
+                    } else if is_cargo_env_var(var.as_str()) {
+                        cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar {
+                            span,
+                            var: *symbol,
+                            var_expr: var_expr.ast_deref(),
+                        })
+                    } else {
+                        cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar {
+                            span,
+                            var: *symbol,
+                            var_expr: var_expr.ast_deref(),
+                        })
+                    }
+                }
+                VarError::NotUnicode(_) => {
+                    cx.dcx().emit_err(errors::EnvNotUnicode { span, var: *symbol })
+                }
             };
 
             return ExpandResult::Ready(DummyResult::any(sp, guar));
         }
-        Some(value) => cx.expr_str(span, value),
+        Ok(value) => cx.expr_str(span, value),
     };
     ExpandResult::Ready(MacEager::expr(e))
 }
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 377aff8fb6c..6b6647ef085 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -459,6 +459,14 @@ pub(crate) enum EnvNotDefined<'a> {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_env_not_unicode)]
+pub(crate) struct EnvNotUnicode {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) var: Symbol,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_format_requires_string)]
 pub(crate) struct FormatRequiresString {
     #[primary_span]
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 6f031f270ca..51d6058a744 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -65,7 +65,7 @@ struct MacroInput {
 /// ```text
 /// Ok((fmtstr, parsed arguments))
 /// ```
-fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> {
+fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> {
     let mut args = FormatArguments::new();
 
     let mut p = ecx.new_parser_from_tts(tts);
@@ -604,7 +604,7 @@ fn invalid_placeholder_type_error(
 }
 
 fn report_missing_placeholders(
-    ecx: &mut ExtCtxt<'_>,
+    ecx: &ExtCtxt<'_>,
     unused: Vec<(Span, bool)>,
     used: &[bool],
     args: &FormatArguments,
@@ -734,7 +734,7 @@ fn report_missing_placeholders(
 /// This function detects and reports unused format!() arguments that are
 /// redundant due to implicit captures (e.g. `format!("{x}", x)`).
 fn report_redundant_format_arguments<'a>(
-    ecx: &mut ExtCtxt<'a>,
+    ecx: &ExtCtxt<'a>,
     args: &FormatArguments,
     used: &[bool],
     placeholders: Vec<(Span, &str)>,
@@ -806,7 +806,7 @@ fn report_redundant_format_arguments<'a>(
 /// there are named arguments or numbered positional arguments in the
 /// format string.
 fn report_invalid_references(
-    ecx: &mut ExtCtxt<'_>,
+    ecx: &ExtCtxt<'_>,
     invalid_refs: &[(usize, Option<Span>, PositionUsedAs, FormatArgPositionKind)],
     template: &[FormatArgsPiece],
     fmt_span: Span,
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index abcdfabcaed..61a6361ae8d 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -234,7 +234,7 @@ pub fn expand_include_bytes(
 }
 
 fn load_binary_file(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     original_path: &Path,
     macro_span: Span,
     path_span: Span,
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 81ac78dd58f..c7568f1461c 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -96,7 +96,7 @@ pub fn expand_bench(
 }
 
 pub fn expand_test_or_bench(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     attr_sp: Span,
     item: Annotatable,
     is_bench: bool,
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 8d0b84f62dc..0aa2bae8f78 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -649,8 +649,8 @@ fn codegen_stmt<'tcx>(
                     | CastKind::IntToFloat
                     | CastKind::FnPtrToPtr
                     | CastKind::PtrToPtr
-                    | CastKind::PointerExposeAddress
-                    | CastKind::PointerFromExposedAddress,
+                    | CastKind::PointerExposeProvenance
+                    | CastKind::PointerWithExposedProvenance,
                     ref operand,
                     to_ty,
                 ) => {
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index b2bc289a5b6..4a5ef352151 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -68,7 +68,7 @@ pub(crate) fn maybe_codegen<'tcx>(
                 Some(CValue::by_val(ret_val, lhs.layout()))
             }
         }
-        BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => None,
+        BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
         BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
     }
 }
@@ -134,6 +134,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
         BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
         BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
         BinOp::Div | BinOp::Rem => unreachable!(),
+        BinOp::Cmp => unreachable!(),
         BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(),
         BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => unreachable!(),
     }
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
index 380eba437c2..32b9c824ded 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
@@ -89,11 +89,7 @@ impl DebugContext {
             match &source_file.name {
                 FileName::Real(path) => {
                     let (dir_path, file_name) =
-                        split_path_dir_and_file(if self.should_remap_filepaths {
-                            path.remapped_path_if_available()
-                        } else {
-                            path.local_path_if_available()
-                        });
+                        split_path_dir_and_file(path.to_path(self.filename_display_preference));
                     let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
                     let file_name = osstr_as_utf8_bytes(file_name);
 
@@ -115,14 +111,7 @@ impl DebugContext {
                 filename => {
                     let dir_id = line_program.default_directory();
                     let dummy_file_name = LineString::new(
-                        filename
-                            .display(if self.should_remap_filepaths {
-                                FileNameDisplayPreference::Remapped
-                            } else {
-                                FileNameDisplayPreference::Local
-                            })
-                            .to_string()
-                            .into_bytes(),
+                        filename.display(self.filename_display_preference).to_string().into_bytes(),
                         line_program.encoding(),
                         line_strings,
                     );
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index 1bb0e590513..5d943b5d996 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -42,7 +42,7 @@ pub(crate) struct DebugContext {
     namespace_map: DefIdMap<UnitEntryId>,
     array_size_type: UnitEntryId,
 
-    should_remap_filepaths: bool,
+    filename_display_preference: FileNameDisplayPreference,
 }
 
 pub(crate) struct FunctionDebugContext {
@@ -84,22 +84,18 @@ impl DebugContext {
 
         let mut dwarf = DwarfUnit::new(encoding);
 
-        let should_remap_filepaths = tcx.sess.should_prefer_remapped_for_codegen();
+        use rustc_session::config::RemapPathScopeComponents;
+
+        let filename_display_preference =
+            tcx.sess.filename_display_preference(RemapPathScopeComponents::DEBUGINFO);
 
         let producer = producer(tcx.sess);
-        let comp_dir = tcx
-            .sess
-            .opts
-            .working_dir
-            .to_string_lossy(if should_remap_filepaths {
-                FileNameDisplayPreference::Remapped
-            } else {
-                FileNameDisplayPreference::Local
-            })
-            .into_owned();
+        let comp_dir =
+            tcx.sess.opts.working_dir.to_string_lossy(filename_display_preference).to_string();
+
         let (name, file_info) = match tcx.sess.local_crate_source_file() {
             Some(path) => {
-                let name = path.to_string_lossy().into_owned();
+                let name = path.to_string_lossy(filename_display_preference).to_string();
                 (name, None)
             }
             None => (tcx.crate_name(LOCAL_CRATE).to_string(), None),
@@ -156,7 +152,7 @@ impl DebugContext {
             stack_pointer_register,
             namespace_map: DefIdMap::default(),
             array_size_type,
-            should_remap_filepaths,
+            filename_display_preference,
         }
     }
 
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index 1615dc5de69..8df83c706a1 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -1393,7 +1393,7 @@ fn llvm_add_sub<'tcx>(
 
     // c + carry -> c + first intermediate carry or borrow respectively
     let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
-    let c = int0.value_field(fx, FieldIdx::new(0));
+    let c = int0.value_field(fx, FieldIdx::ZERO);
     let cb0 = int0.value_field(fx, FieldIdx::new(1)).load_scalar(fx);
 
     // c + carry -> c + second intermediate carry or borrow respectively
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 4d55a95aa9d..67f9d831062 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -965,7 +965,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             });
         }
 
-        sym::simd_expose_addr | sym::simd_from_exposed_addr | sym::simd_cast_ptr => {
+        sym::simd_expose_provenance | sym::simd_with_exposed_provenance | sym::simd_cast_ptr => {
             intrinsic_args!(fx, args => (arg); intrinsic);
             ret.write_cvalue_transmute(fx, arg);
         }
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index 8992f40fb90..796182418ad 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -40,6 +40,22 @@ pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
     })
 }
 
+fn codegen_three_way_compare<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    signed: bool,
+    lhs: Value,
+    rhs: Value,
+) -> CValue<'tcx> {
+    // This emits `(lhs > rhs) - (lhs < rhs)`, which is cranelift's preferred form per
+    // <https://github.com/bytecodealliance/wasmtime/blob/8052bb9e3b792503b225f2a5b2ba3bc023bff462/cranelift/codegen/src/prelude_opt.isle#L41-L47>
+    let gt_cc = crate::num::bin_op_to_intcc(BinOp::Gt, signed).unwrap();
+    let lt_cc = crate::num::bin_op_to_intcc(BinOp::Lt, signed).unwrap();
+    let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs);
+    let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs);
+    let val = fx.bcx.ins().isub(gt, lt);
+    CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(Some(fx.mir.span))))
+}
+
 fn codegen_compare_bin_op<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     bin_op: BinOp,
@@ -47,6 +63,10 @@ fn codegen_compare_bin_op<'tcx>(
     lhs: Value,
     rhs: Value,
 ) -> CValue<'tcx> {
+    if bin_op == BinOp::Cmp {
+        return codegen_three_way_compare(fx, signed, lhs, rhs);
+    }
+
     let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
     let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
     CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
@@ -59,7 +79,7 @@ pub(crate) fn codegen_binop<'tcx>(
     in_rhs: CValue<'tcx>,
 ) -> CValue<'tcx> {
     match bin_op {
-        BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
+        BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt | BinOp::Cmp => {
             match in_lhs.layout().ty.kind() {
                 ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
                     let signed = type_sign(in_lhs.layout().ty);
@@ -160,7 +180,7 @@ pub(crate) fn codegen_int_binop<'tcx>(
         }
         BinOp::Offset => unreachable!("Offset is not an integer operation"),
         // Compare binops handles by `codegen_binop`.
-        BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
+        BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Cmp => {
             unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty);
         }
     };
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 86ebf37d105..04e24320f91 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -61,7 +61,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
             if ty.is_dyn_star() {
                 let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap().ty);
                 let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout);
-                let ptr = dyn_star.place_field(fx, FieldIdx::new(0)).to_ptr();
+                let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr();
                 let vtable =
                     dyn_star.place_field(fx, FieldIdx::new(1)).to_cvalue(fx).load_scalar(fx);
                 break 'block (ptr, vtable);
diff --git a/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
index 914ae986b50..36d0789d2a2 100644
--- a/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
+++ b/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
@@ -14,7 +14,7 @@ index d0a119c..76fdece 100644
 @@ -89,7 +89,6 @@
  #![feature(never_type)]
  #![feature(unwrap_infallible)]
- #![feature(pointer_is_aligned)]
+ #![feature(pointer_is_aligned_to)]
 -#![feature(portable_simd)]
  #![feature(ptr_metadata)]
  #![feature(lazy_cell)]
@@ -27,6 +27,6 @@ index d0a119c..76fdece 100644
  mod slice;
  mod str;
  mod str_lossy;
--- 
+--
 2.42.1
 
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index d243d7088ad..78d943192db 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -94,6 +94,10 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         self.const_int(self.type_i32(), i as i64)
     }
 
+    fn const_i8(&self, i: i8) -> RValue<'gcc> {
+        self.const_int(self.type_i8(), i as i64)
+    }
+
     fn const_u32(&self, i: u32) -> RValue<'gcc> {
         self.const_uint(self.type_u32(), i as u64)
     }
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index e5f5146fac8..d2828669d43 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -16,13 +16,15 @@ pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
 use rustc_middle::ty::Ty;
 use rustc_session::config;
 pub use rustc_target::abi::call::*;
-use rustc_target::abi::{self, HasDataLayout, Int};
+use rustc_target::abi::{self, HasDataLayout, Int, Size};
 pub use rustc_target::spec::abi::Abi;
 use rustc_target::spec::SanitizerSet;
 
 use libc::c_uint;
 use smallvec::SmallVec;
 
+use std::cmp;
+
 pub trait ArgAttributesExt {
     fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value);
     fn apply_attrs_to_callsite(
@@ -130,42 +132,36 @@ impl LlvmType for Reg {
 impl LlvmType for CastTarget {
     fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
         let rest_ll_unit = self.rest.unit.llvm_type(cx);
-        let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 {
-            (0, 0)
+        let rest_count = if self.rest.total == Size::ZERO {
+            0
         } else {
-            (
-                self.rest.total.bytes() / self.rest.unit.size.bytes(),
-                self.rest.total.bytes() % self.rest.unit.size.bytes(),
-            )
+            assert_ne!(
+                self.rest.unit.size,
+                Size::ZERO,
+                "total size {:?} cannot be divided into units of zero size",
+                self.rest.total
+            );
+            if self.rest.total.bytes() % self.rest.unit.size.bytes() != 0 {
+                assert_eq!(self.rest.unit.kind, RegKind::Integer, "only int regs can be split");
+            }
+            self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes())
         };
 
+        // Simplify to a single unit or an array if there's no prefix.
+        // This produces the same layout, but using a simpler type.
         if self.prefix.iter().all(|x| x.is_none()) {
-            // Simplify to a single unit when there is no prefix and size <= unit size
-            if self.rest.total <= self.rest.unit.size {
+            if rest_count == 1 {
                 return rest_ll_unit;
             }
 
-            // Simplify to array when all chunks are the same size and type
-            if rem_bytes == 0 {
-                return cx.type_array(rest_ll_unit, rest_count);
-            }
-        }
-
-        // Create list of fields in the main structure
-        let mut args: Vec<_> = self
-            .prefix
-            .iter()
-            .flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx)))
-            .chain((0..rest_count).map(|_| rest_ll_unit))
-            .collect();
-
-        // Append final integer
-        if rem_bytes != 0 {
-            // Only integers can be really split further.
-            assert_eq!(self.rest.unit.kind, RegKind::Integer);
-            args.push(cx.type_ix(rem_bytes * 8));
+            return cx.type_array(rest_ll_unit, rest_count);
         }
 
+        // Generate a struct type with the prefix and the "rest" arguments.
+        let prefix_args =
+            self.prefix.iter().flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx)));
+        let rest_args = (0..rest_count).map(|_| rest_ll_unit);
+        let args: Vec<_> = prefix_args.chain(rest_args).collect();
         cx.type_struct(&args, false)
     }
 }
@@ -215,47 +211,33 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
             }
             PassMode::Cast { cast, pad_i32: _ } => {
-                // FIXME(eddyb): Figure out when the simpler Store is safe, clang
-                // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
-                let can_store_through_cast_ptr = false;
-                if can_store_through_cast_ptr {
-                    bx.store(val, dst.llval, self.layout.align.abi);
-                } else {
-                    // The actual return type is a struct, but the ABI
-                    // adaptation code has cast it into some scalar type. The
-                    // code that follows is the only reliable way I have
-                    // found to do a transform like i64 -> {i32,i32}.
-                    // Basically we dump the data onto the stack then memcpy it.
-                    //
-                    // Other approaches I tried:
-                    // - Casting rust ret pointer to the foreign type and using Store
-                    //   is (a) unsafe if size of foreign type > size of rust type and
-                    //   (b) runs afoul of strict aliasing rules, yielding invalid
-                    //   assembly under -O (specifically, the store gets removed).
-                    // - Truncating foreign type to correct integral type and then
-                    //   bitcasting to the struct type yields invalid cast errors.
-
-                    // We instead thus allocate some scratch space...
-                    let scratch_size = cast.size(bx);
-                    let scratch_align = cast.align(bx);
-                    let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align);
-                    bx.lifetime_start(llscratch, scratch_size);
-
-                    // ... where we first store the value...
-                    bx.store(val, llscratch, scratch_align);
-
-                    // ... and then memcpy it to the intended destination.
-                    bx.memcpy(
-                        dst.llval,
-                        self.layout.align.abi,
-                        llscratch,
-                        scratch_align,
-                        bx.const_usize(self.layout.size.bytes()),
-                        MemFlags::empty(),
-                    );
-
-                    bx.lifetime_end(llscratch, scratch_size);
-                }
+                // The ABI mandates that the value is passed as a different struct representation.
+                // Spill and reload it from the stack to convert from the ABI representation to
+                // the Rust representation.
+                let scratch_size = cast.size(bx);
+                let scratch_align = cast.align(bx);
+                // Note that the ABI type may be either larger or smaller than the Rust type,
+                // due to the presence or absence of trailing padding. For example:
+                // - On some ABIs, the Rust layout { f64, f32, <f32 padding> } may omit padding
+                //   when passed by value, making it smaller.
+                // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
+                //   when passed by value, making it larger.
+                let copy_bytes = cmp::min(scratch_size.bytes(), self.layout.size.bytes());
+                // Allocate some scratch space...
+                let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align);
+                bx.lifetime_start(llscratch, scratch_size);
+                // ...store the value...
+                bx.store(val, llscratch, scratch_align);
+                // ... and then memcpy it to the intended destination.
+                bx.memcpy(
+                    dst.llval,
+                    self.layout.align.abi,
+                    llscratch,
+                    scratch_align,
+                    bx.const_usize(copy_bytes),
+                    MemFlags::empty(),
+                );
+                bx.lifetime_end(llscratch, scratch_size);
             }
             _ => {
                 OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst);
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index f9eaa0d94cb..870e5ab3296 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -417,7 +417,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
         to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry"));
     }
     if let Some(align) = codegen_fn_attrs.alignment {
-        llvm::set_alignment(llfn, align as usize);
+        llvm::set_alignment(llfn, align);
     }
     to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));
 
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 031bbd63361..4efea66a7f1 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -29,7 +29,8 @@ use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_errors::{DiagCtxt, FatalError, Level};
 use rustc_fs_util::{link_or_copy, path_to_c_string};
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
+use rustc_session::config::{self, Lto, OutputType, Passes};
+use rustc_session::config::{RemapPathScopeComponents, SplitDwarfKind, SwitchWithOptPath};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::InnerSpan;
@@ -257,18 +258,17 @@ pub fn target_machine_factory(
     };
     let debuginfo_compression = SmallCStr::new(&debuginfo_compression);
 
-    let should_prefer_remapped_for_split_debuginfo_paths =
-        sess.should_prefer_remapped_for_split_debuginfo_paths();
+    let file_name_display_preference =
+        sess.filename_display_preference(RemapPathScopeComponents::DEBUGINFO);
 
     Arc::new(move |config: TargetMachineFactoryConfig| {
         let path_to_cstring_helper = |path: Option<PathBuf>| -> CString {
             let path = path.unwrap_or_default();
-            let path = if should_prefer_remapped_for_split_debuginfo_paths {
-                path_mapping.map_prefix(path).0
-            } else {
-                path.into()
-            };
-            CString::new(path.to_str().unwrap()).unwrap()
+            let path = path_mapping
+                .to_real_filename(path)
+                .to_string_lossy(file_name_display_preference)
+                .into_owned();
+            CString::new(path).unwrap()
         };
 
         let split_dwarf_file = path_to_cstring_helper(config.split_dwarf_file);
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 25cbd90460f..568fcc3f3cf 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -160,6 +160,10 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         self.const_int(self.type_i32(), i as i64)
     }
 
+    fn const_i8(&self, i: i8) -> &'ll Value {
+        self.const_int(self.type_i8(), i as i64)
+    }
+
     fn const_u32(&self, i: u32) -> &'ll Value {
         self.const_uint(self.type_i32(), i as u64)
     }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 0fbc624389b..278db21b0a1 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -173,8 +173,14 @@ impl GlobalFileTable {
         // Since rustc generates coverage maps with relative paths, the
         // compilation directory can be combined with the relative paths
         // to get absolute paths, if needed.
+        use rustc_session::config::RemapPathScopeComponents;
         use rustc_session::RemapFileNameExt;
-        let working_dir: &str = &tcx.sess.opts.working_dir.for_codegen(tcx.sess).to_string_lossy();
+        let working_dir: &str = &tcx
+            .sess
+            .opts
+            .working_dir
+            .for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
+            .to_string_lossy();
 
         llvm::build_byte_buffer(|buffer| {
             coverageinfo::write_filenames_section_to_buffer(
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 85277db6d53..68c1770c1d4 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -16,6 +16,7 @@ use rustc_middle::bug;
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::Instance;
+use rustc_target::abi::Align;
 
 use std::cell::RefCell;
 
@@ -23,7 +24,7 @@ pub(crate) mod ffi;
 pub(crate) mod map_data;
 pub mod mapgen;
 
-const VAR_ALIGN_BYTES: usize = 8;
+const VAR_ALIGN: Align = Align::EIGHT;
 
 /// A context object for maintaining all state needed by the coverageinfo module.
 pub struct CrateCoverageContext<'ll, 'tcx> {
@@ -225,7 +226,7 @@ pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
     llvm::set_global_constant(llglobal, true);
     llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
     llvm::set_section(llglobal, &covmap_section_name);
-    llvm::set_alignment(llglobal, VAR_ALIGN_BYTES);
+    llvm::set_alignment(llglobal, VAR_ALIGN);
     cx.add_used_global(llglobal);
 }
 
@@ -255,7 +256,7 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
     llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
     llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
     llvm::set_section(llglobal, covfun_section_name);
-    llvm::set_alignment(llglobal, VAR_ALIGN_BYTES);
+    llvm::set_alignment(llglobal, VAR_ALIGN);
     llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
     cx.add_used_global(llglobal);
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 3c76df11e3f..e5fecddec52 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -554,13 +554,16 @@ pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) ->
     ) -> &'ll DIFile {
         debug!(?source_file.name);
 
-        use rustc_session::RemapFileNameExt;
+        let filename_display_preference =
+            cx.sess().filename_display_preference(RemapPathScopeComponents::DEBUGINFO);
+
+        use rustc_session::config::RemapPathScopeComponents;
         let (directory, file_name) = match &source_file.name {
             FileName::Real(filename) => {
                 let working_directory = &cx.sess().opts.working_dir;
                 debug!(?working_directory);
 
-                if cx.sess().should_prefer_remapped_for_codegen() {
+                if filename_display_preference == FileNameDisplayPreference::Remapped {
                     let filename = cx
                         .sess()
                         .source_map()
@@ -623,7 +626,7 @@ pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) ->
             }
             other => {
                 debug!(?other);
-                ("".into(), other.for_codegen(cx.sess()).to_string_lossy().into_owned())
+                ("".into(), other.display(filename_display_preference).to_string())
             }
         };
 
@@ -832,9 +835,11 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
     codegen_unit_name: &str,
     debug_context: &CodegenUnitDebugContext<'ll, 'tcx>,
 ) -> &'ll DIDescriptor {
+    use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
     let mut name_in_debuginfo = tcx
         .sess
         .local_crate_source_file()
+        .map(|src| src.for_scope(&tcx.sess, RemapPathScopeComponents::DEBUGINFO).to_path_buf())
         .unwrap_or_else(|| PathBuf::from(tcx.crate_name(LOCAL_CRATE).as_str()));
 
     // To avoid breaking split DWARF, we need to ensure that each codegen unit
@@ -862,30 +867,29 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
     // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
     let producer = format!("clang LLVM ({rustc_producer})");
 
-    use rustc_session::RemapFileNameExt;
     let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
-    let work_dir = tcx.sess.opts.working_dir.for_codegen(tcx.sess).to_string_lossy();
+    let work_dir = tcx
+        .sess
+        .opts
+        .working_dir
+        .for_scope(tcx.sess, RemapPathScopeComponents::DEBUGINFO)
+        .to_string_lossy();
     let output_filenames = tcx.output_filenames(());
-    let split_name = if tcx.sess.target_can_use_split_dwarf() {
-        output_filenames
-            .split_dwarf_path(
-                tcx.sess.split_debuginfo(),
-                tcx.sess.opts.unstable_opts.split_dwarf_kind,
-                Some(codegen_unit_name),
-            )
-            // We get a path relative to the working directory from split_dwarf_path
-            .map(|f| {
-                if tcx.sess.should_prefer_remapped_for_split_debuginfo_paths() {
-                    tcx.sess.source_map().path_mapping().map_prefix(f).0
-                } else {
-                    f.into()
-                }
-            })
+    let split_name = if tcx.sess.target_can_use_split_dwarf()
+        && let Some(f) = output_filenames.split_dwarf_path(
+            tcx.sess.split_debuginfo(),
+            tcx.sess.opts.unstable_opts.split_dwarf_kind,
+            Some(codegen_unit_name),
+        ) {
+        // We get a path relative to the working directory from split_dwarf_path
+        Some(tcx.sess.source_map().path_mapping().to_real_filename(f))
     } else {
         None
-    }
-    .unwrap_or_default();
-    let split_name = split_name.to_str().unwrap();
+    };
+    let split_name = split_name
+        .as_ref()
+        .map(|f| f.for_scope(tcx.sess, RemapPathScopeComponents::DEBUGINFO).to_string_lossy())
+        .unwrap_or_default();
     let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
 
     let dwarf_version =
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 3ef8538ced3..f58dd4066ad 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -147,7 +147,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
                 for options in [
                     TypeIdOptions::GENERALIZE_POINTERS,
                     TypeIdOptions::NORMALIZE_INTEGERS,
-                    TypeIdOptions::NO_SELF_TYPE_ERASURE,
+                    TypeIdOptions::ERASE_SELF_TYPE,
                 ]
                 .into_iter()
                 .powerset()
@@ -173,7 +173,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 
         if self.tcx.sess.is_sanitizer_kcfi_enabled() {
             // LLVM KCFI does not support multiple !kcfi_type attachments
-            let mut options = TypeIdOptions::empty();
+            // Default to erasing the self type. If we need the concrete type, there will be a
+            // hint in the instance.
+            let mut options = TypeIdOptions::ERASE_SELF_TYPE;
             if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
                 options.insert(TypeIdOptions::GENERALIZE_POINTERS);
             }
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index ab135e3ed64..dc52dd156b7 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -2111,7 +2111,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         return Ok(args[0].immediate());
     }
 
-    if name == sym::simd_expose_addr {
+    if name == sym::simd_expose_provenance {
         let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
         require!(
             in_len == out_len,
@@ -2139,7 +2139,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         return Ok(bx.ptrtoint(args[0].immediate(), llret_ty));
     }
 
-    if name == sym::simd_from_exposed_addr {
+    if name == sym::simd_with_exposed_provenance {
         let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
         require!(
             in_len == out_len,
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 4f5cc575da6..6ab1eea9597 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -11,6 +11,7 @@ pub use self::RealPredicate::*;
 use libc::c_uint;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_llvm::RustString;
+use rustc_target::abi::Align;
 use std::cell::RefCell;
 use std::ffi::{CStr, CString};
 use std::str::FromStr;
@@ -229,9 +230,9 @@ pub fn set_visibility(llglobal: &Value, visibility: Visibility) {
     }
 }
 
-pub fn set_alignment(llglobal: &Value, bytes: usize) {
+pub fn set_alignment(llglobal: &Value, align: Align) {
     unsafe {
-        ffi::LLVMSetAlignment(llglobal, bytes as c_uint);
+        ffi::LLVMSetAlignment(llglobal, align.bytes() as c_uint);
     }
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index c8b8594c0dd..7c7f702b2c3 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2089,14 +2089,14 @@ fn add_rpath_args(
                     .map(|(path, _)| &**path)
             })
             .collect::<Vec<_>>();
-        let mut rpath_config = RPathConfig {
+        let rpath_config = RPathConfig {
             libs: &*libs,
             out_filename: out_filename.to_path_buf(),
             has_rpath: sess.target.has_rpath,
             is_like_osx: sess.target.is_like_osx,
             linker_is_gnu: sess.target.linker_flavor.is_gnu(),
         };
-        cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
+        cmd.args(&rpath::get_rpath_flags(&rpath_config));
     }
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs
index 60346228625..ebbf49af184 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs
@@ -12,7 +12,7 @@ pub struct RPathConfig<'a> {
     pub linker_is_gnu: bool,
 }
 
-pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<OsString> {
+pub fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec<OsString> {
     // No rpath on windows
     if !config.has_rpath {
         return Vec::new();
@@ -52,7 +52,7 @@ fn rpaths_to_flags(rpaths: Vec<OsString>) -> Vec<OsString> {
     ret
 }
 
-fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec<OsString> {
+fn get_rpaths(config: &RPathConfig<'_>) -> Vec<OsString> {
     debug!("output: {:?}", config.out_filename.display());
     debug!("libs:");
     for libpath in config.libs {
@@ -73,11 +73,11 @@ fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec<OsString> {
     minimize_rpaths(&rpaths)
 }
 
-fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>) -> Vec<OsString> {
+fn get_rpaths_relative_to_output(config: &RPathConfig<'_>) -> Vec<OsString> {
     config.libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect()
 }
 
-fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> OsString {
+fn get_rpath_relative_to_output(config: &RPathConfig<'_>, lib: &Path) -> OsString {
     // Mac doesn't appear to support $ORIGIN
     let prefix = if config.is_like_osx { "@loader_path" } else { "$ORIGIN" };
 
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index f7f2bfca838..410b5d27c57 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -5,7 +5,7 @@ use crate::back::write::{
     compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
     submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
 };
-use crate::common::{IntPredicate, RealPredicate, TypeKind};
+use crate::common::{self, IntPredicate, RealPredicate, TypeKind};
 use crate::errors;
 use crate::meth;
 use crate::mir;
@@ -33,7 +33,7 @@ use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
-use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
+use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::Symbol;
@@ -300,14 +300,35 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 }
 
-pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+/// Returns `rhs` sufficiently masked, truncated, and/or extended so that
+/// it can be used to shift `lhs`.
+///
+/// Shifts in MIR are all allowed to have mismatched LHS & RHS types.
+/// The shift methods in `BuilderMethods`, however, are fully homogeneous
+/// (both parameters and the return type are all the same type).
+///
+/// If `is_unchecked` is false, this masks the RHS to ensure it stays in-bounds,
+/// as the `BuilderMethods` shifts are UB for out-of-bounds shift amounts.
+/// For 32- and 64-bit types, this matches the semantics
+/// of Java. (See related discussion on #1877 and #10183.)
+///
+/// If `is_unchecked` is true, this does no masking, and adds sufficient `assume`
+/// calls or operation flags to preserve as much freedom to optimize as possible.
+pub fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
     lhs: Bx::Value,
-    rhs: Bx::Value,
+    mut rhs: Bx::Value,
+    is_unchecked: bool,
 ) -> Bx::Value {
     // Shifts may have any size int on the rhs
     let mut rhs_llty = bx.cx().val_ty(rhs);
     let mut lhs_llty = bx.cx().val_ty(lhs);
+
+    let mask = common::shift_mask_val(bx, lhs_llty, rhs_llty, false);
+    if !is_unchecked {
+        rhs = bx.and(rhs, mask);
+    }
+
     if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
         rhs_llty = bx.cx().element_type(rhs_llty)
     }
@@ -317,6 +338,12 @@ pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     let rhs_sz = bx.cx().int_width(rhs_llty);
     let lhs_sz = bx.cx().int_width(lhs_llty);
     if lhs_sz < rhs_sz {
+        if is_unchecked && bx.sess().opts.optimize != OptLevel::No {
+            // FIXME: Use `trunc nuw` once that's available
+            let inrange = bx.icmp(IntPredicate::IntULE, rhs, mask);
+            bx.assume(inrange);
+        }
+
         bx.trunc(rhs, lhs_llty)
     } else if lhs_sz > rhs_sz {
         // We zero-extend even if the RHS is signed. So e.g. `(x: i32) << -1i8` will zero-extend the
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index 71fca403def..b41739867c7 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -3,10 +3,9 @@
 use rustc_hir::LangItem;
 use rustc_middle::mir;
 use rustc_middle::ty::Instance;
-use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
+use rustc_middle::ty::{self, layout::TyAndLayout, TyCtxt};
 use rustc_span::Span;
 
-use crate::base;
 use crate::traits::*;
 
 #[derive(Copy, Clone)]
@@ -128,44 +127,6 @@ pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance)
 }
 
-// To avoid UB from LLVM, these two functions mask RHS with an
-// appropriate mask unconditionally (i.e., the fallback behavior for
-// all shifts). For 32- and 64-bit types, this matches the semantics
-// of Java. (See related discussion on #1877 and #10183.)
-
-pub fn build_masked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    bx: &mut Bx,
-    lhs: Bx::Value,
-    rhs: Bx::Value,
-) -> Bx::Value {
-    let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
-    // #1877, #10183: Ensure that input is always valid
-    let rhs = shift_mask_rhs(bx, rhs);
-    bx.shl(lhs, rhs)
-}
-
-pub fn build_masked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    bx: &mut Bx,
-    lhs_t: Ty<'tcx>,
-    lhs: Bx::Value,
-    rhs: Bx::Value,
-) -> Bx::Value {
-    let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
-    // #1877, #10183: Ensure that input is always valid
-    let rhs = shift_mask_rhs(bx, rhs);
-    let is_signed = lhs_t.is_signed();
-    if is_signed { bx.ashr(lhs, rhs) } else { bx.lshr(lhs, rhs) }
-}
-
-fn shift_mask_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    bx: &mut Bx,
-    rhs: Bx::Value,
-) -> Bx::Value {
-    let rhs_llty = bx.val_ty(rhs);
-    let shift_val = shift_mask_val(bx, rhs_llty, rhs_llty, false);
-    bx.and(rhs, shift_val)
-}
-
 pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
     llty: Bx::Type,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index d4123329f44..1aa52a985ef 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1505,9 +1505,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         if by_ref && !arg.is_indirect() {
             // Have to load the argument, maybe while casting it.
-            if let PassMode::Cast { cast: ty, .. } = &arg.mode {
-                let llty = bx.cast_backend_type(ty);
-                llval = bx.load(llty, llval, align.min(arg.layout.align.abi));
+            if let PassMode::Cast { cast, pad_i32: _ } = &arg.mode {
+                // The ABI mandates that the value is passed as a different struct representation.
+                // Spill and reload it from the stack to convert from the Rust representation to
+                // the ABI representation.
+                let scratch_size = cast.size(bx);
+                let scratch_align = cast.align(bx);
+                // Note that the ABI type may be either larger or smaller than the Rust type,
+                // due to the presence or absence of trailing padding. For example:
+                // - On some ABIs, the Rust layout { f64, f32, <f32 padding> } may omit padding
+                //   when passed by value, making it smaller.
+                // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
+                //   when passed by value, making it larger.
+                let copy_bytes = cmp::min(scratch_size.bytes(), arg.layout.size.bytes());
+                // Allocate some scratch space...
+                let llscratch = bx.alloca(bx.cast_backend_type(cast), scratch_align);
+                bx.lifetime_start(llscratch, scratch_size);
+                // ...memcpy the value...
+                bx.memcpy(
+                    llscratch,
+                    scratch_align,
+                    llval,
+                    align,
+                    bx.const_usize(copy_bytes),
+                    MemFlags::empty(),
+                );
+                // ...and then load it with the ABI type.
+                let cast_ty = bx.cast_backend_type(cast);
+                llval = bx.load(cast_ty, llscratch, scratch_align);
+                bx.lifetime_end(llscratch, scratch_size);
             } else {
                 // We can't use `PlaceRef::load` here because the argument
                 // may have a type we don't treat as immediate, but the ABI
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 0af84ff067a..4d746c89f1f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -3,10 +3,11 @@ use super::place::PlaceRef;
 use super::{FunctionCx, LocalRef};
 
 use crate::base;
-use crate::common::{self, IntPredicate};
+use crate::common::IntPredicate;
 use crate::traits::*;
 use crate::MemFlags;
 
+use rustc_hir as hir;
 use rustc_middle::mir;
 use rustc_middle::mir::Operand;
 use rustc_middle::ty::cast::{CastTy, IntTy};
@@ -404,7 +405,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty));
 
                 let val = match *kind {
-                    mir::CastKind::PointerExposeAddress => {
+                    mir::CastKind::PointerExposeProvenance => {
                         assert!(bx.cx().is_backend_immediate(cast));
                         let llptr = operand.immediate();
                         let llcast_ty = bx.cx().immediate_backend_type(cast);
@@ -508,7 +509,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     // Since int2ptr can have arbitrary integer types as input (so we have to do
                     // sign extension and all that), it is currently best handled in the same code
                     // path as the other integer-to-X casts.
-                    | mir::CastKind::PointerFromExposedAddress => {
+                    | mir::CastKind::PointerWithExposedProvenance => {
                         assert!(bx.cx().is_backend_immediate(cast));
                         let ll_t_out = bx.cx().immediate_backend_type(cast);
                         if operand.layout.abi.is_uninhabited() {
@@ -860,14 +861,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     bx.inbounds_gep(llty, lhs, &[rhs])
                 }
             }
-            mir::BinOp::Shl => common::build_masked_lshift(bx, lhs, rhs),
-            mir::BinOp::ShlUnchecked => {
-                let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
+            mir::BinOp::Shl | mir::BinOp::ShlUnchecked => {
+                let rhs = base::build_shift_expr_rhs(bx, lhs, rhs, op == mir::BinOp::ShlUnchecked);
                 bx.shl(lhs, rhs)
             }
-            mir::BinOp::Shr => common::build_masked_rshift(bx, input_ty, lhs, rhs),
-            mir::BinOp::ShrUnchecked => {
-                let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
+            mir::BinOp::Shr | mir::BinOp::ShrUnchecked => {
+                let rhs = base::build_shift_expr_rhs(bx, lhs, rhs, op == mir::BinOp::ShrUnchecked);
                 if is_signed { bx.ashr(lhs, rhs) } else { bx.lshr(lhs, rhs) }
             }
             mir::BinOp::Ne
@@ -882,6 +881,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     bx.icmp(base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), lhs, rhs)
                 }
             }
+            mir::BinOp::Cmp => {
+                use std::cmp::Ordering;
+                debug_assert!(!is_float);
+                let pred = |op| base::bin_op_to_icmp_predicate(op, is_signed);
+                if bx.cx().tcx().sess.opts.optimize == OptLevel::No {
+                    // FIXME: This actually generates tighter assembly, and is a classic trick
+                    // <https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>
+                    // However, as of 2023-11 it optimizes worse in things like derived
+                    // `PartialOrd`, so only use it in debug for now. Once LLVM can handle it
+                    // better (see <https://github.com/llvm/llvm-project/issues/73417>), it'll
+                    // be worth trying it in optimized builds as well.
+                    let is_gt = bx.icmp(pred(hir::BinOpKind::Gt), lhs, rhs);
+                    let gtext = bx.zext(is_gt, bx.type_i8());
+                    let is_lt = bx.icmp(pred(hir::BinOpKind::Lt), lhs, rhs);
+                    let ltext = bx.zext(is_lt, bx.type_i8());
+                    bx.unchecked_ssub(gtext, ltext)
+                } else {
+                    // These operations are those expected by `tests/codegen/integer-cmp.rs`,
+                    // from <https://github.com/rust-lang/rust/pull/63767>.
+                    let is_lt = bx.icmp(pred(hir::BinOpKind::Lt), lhs, rhs);
+                    let is_ne = bx.icmp(pred(hir::BinOpKind::Ne), lhs, rhs);
+                    let ge = bx.select(
+                        is_ne,
+                        bx.cx().const_i8(Ordering::Greater as i8),
+                        bx.cx().const_i8(Ordering::Equal as i8),
+                    );
+                    bx.select(is_lt, bx.cx().const_i8(Ordering::Less as i8), ge)
+                }
+            }
         }
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index 4dff9c7684f..8cb17a5b37a 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -19,6 +19,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
     fn const_bool(&self, val: bool) -> Self::Value;
     fn const_i16(&self, i: i16) -> Self::Value;
     fn const_i32(&self, i: i32) -> Self::Value;
+    fn const_i8(&self, i: i8) -> Self::Value;
     fn const_u32(&self, i: u32) -> Self::Value;
     fn const_u64(&self, i: u64) -> Self::Value;
     fn const_u128(&self, i: u128) -> Self::Value;
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index d6aae60c338..f6937dc145d 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -222,6 +222,7 @@ const_eval_mut_deref =
 
 const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
 
+const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead
 const_eval_non_const_fmt_macro_call =
     cannot call non-const formatting macro in {const_eval_const_context}s
 
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 5c46ec799f1..a60cedd6500 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -25,6 +25,13 @@ pub(crate) struct DanglingPtrInFinal {
     pub kind: InternKind,
 }
 
+#[derive(Diagnostic)]
+#[diag(const_eval_nested_static_in_thread_local)]
+pub(crate) struct NestedStaticInThreadLocal {
+    #[primary_span]
+    pub span: Span,
+}
+
 #[derive(LintDiagnostic)]
 #[diag(const_eval_mutable_ptr_in_final)]
 pub(crate) struct MutablePtrInFinal {
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index bbf11f169f9..9447d18fe8c 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -34,15 +34,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.unsize_into(src, cast_layout, dest)?;
             }
 
-            CastKind::PointerExposeAddress => {
+            CastKind::PointerExposeProvenance => {
                 let src = self.read_immediate(src)?;
-                let res = self.pointer_expose_address_cast(&src, cast_layout)?;
+                let res = self.pointer_expose_provenance_cast(&src, cast_layout)?;
                 self.write_immediate(*res, dest)?;
             }
 
-            CastKind::PointerFromExposedAddress => {
+            CastKind::PointerWithExposedProvenance => {
                 let src = self.read_immediate(src)?;
-                let res = self.pointer_from_exposed_address_cast(&src, cast_layout)?;
+                let res = self.pointer_with_exposed_provenance_cast(&src, cast_layout)?;
                 self.write_immediate(*res, dest)?;
             }
 
@@ -225,7 +225,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
     }
 
-    pub fn pointer_expose_address_cast(
+    pub fn pointer_expose_provenance_cast(
         &mut self,
         src: &ImmTy<'tcx, M::Provenance>,
         cast_to: TyAndLayout<'tcx>,
@@ -242,7 +242,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to))
     }
 
-    pub fn pointer_from_exposed_address_cast(
+    pub fn pointer_with_exposed_provenance_cast(
         &self,
         src: &ImmTy<'tcx, M::Provenance>,
         cast_to: TyAndLayout<'tcx>,
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 58eaef65e55..d0f0190fea7 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -18,6 +18,7 @@ use rustc_ast::Mutability;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::TyAndLayout;
@@ -27,7 +28,7 @@ use rustc_span::sym;
 
 use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
 use crate::const_eval;
-use crate::errors::{DanglingPtrInFinal, MutablePtrInFinal};
+use crate::errors::{DanglingPtrInFinal, MutablePtrInFinal, NestedStaticInThreadLocal};
 
 pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
         'mir,
@@ -106,13 +107,21 @@ fn intern_as_new_static<'tcx>(
         DefKind::Static { mutability: alloc.0.mutability, nested: true },
     );
     tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());
-    feed.codegen_fn_attrs(tcx.codegen_fn_attrs(static_id).clone());
+
+    if tcx.is_thread_local_static(static_id.into()) {
+        tcx.dcx().emit_err(NestedStaticInThreadLocal { span: tcx.def_span(static_id) });
+    }
+
+    // These do not inherit the codegen attrs of the parent static allocation, since
+    // it doesn't make sense for them to inherit their `#[no_mangle]` and `#[link_name = ..]`
+    // and the like.
+    feed.codegen_fn_attrs(CodegenFnAttrs::new());
+
     feed.eval_static_initializer(Ok(alloc));
     feed.generics_of(tcx.generics_of(static_id).clone());
     feed.def_ident_span(tcx.def_ident_span(static_id));
     feed.explicit_predicates_of(tcx.explicit_predicates_of(static_id));
-
-    feed.feed_hir()
+    feed.feed_hir();
 }
 
 /// How a constant value should be interned.
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index dbc6a317640..842fb6d204c 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -236,6 +236,13 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
     }
 
     #[inline]
+    pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
+        let ty = tcx.ty_ordering_enum(None);
+        let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
+        Self::from_scalar(Scalar::from_i8(c as i8), layout)
+    }
+
+    #[inline]
     pub fn to_const_int(self) -> ConstInt {
         assert!(self.layout.ty.is_integral());
         let int = self.to_scalar().assert_int();
@@ -785,7 +792,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 475c533077a..5665bb4999f 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -61,6 +61,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 }
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
+    fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> (ImmTy<'tcx, M::Provenance>, bool) {
+        let res = Ord::cmp(&lhs, &rhs);
+        return (ImmTy::from_ordering(res, *self.tcx), false);
+    }
+
     fn binary_char_op(
         &self,
         bin_op: mir::BinOp,
@@ -69,6 +74,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     ) -> (ImmTy<'tcx, M::Provenance>, bool) {
         use rustc_middle::mir::BinOp::*;
 
+        if bin_op == Cmp {
+            return self.three_way_compare(l, r);
+        }
+
         let res = match bin_op {
             Eq => l == r,
             Ne => l != r,
@@ -231,6 +240,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let r = self.sign_extend(r, right_layout) as i128;
                 return Ok((ImmTy::from_bool(op(&l, &r), *self.tcx), false));
             }
+            if bin_op == Cmp {
+                let l = self.sign_extend(l, left_layout) as i128;
+                let r = self.sign_extend(r, right_layout) as i128;
+                return Ok(self.three_way_compare(l, r));
+            }
             let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
                 Div if r == 0 => throw_ub!(DivisionByZero),
                 Rem if r == 0 => throw_ub!(RemainderByZero),
@@ -270,6 +284,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
         }
 
+        if bin_op == Cmp {
+            return Ok(self.three_way_compare(l, r));
+        }
+
         let val = match bin_op {
             Eq => ImmTy::from_bool(l == r, *self.tcx),
             Ne => ImmTy::from_bool(l != r, *self.tcx),
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 1a2f1194f89..e32aea39fc5 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -1058,7 +1058,7 @@ where
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index da8e28d0298..543996c86ba 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -544,10 +544,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 // Unsizing is implemented for CTFE.
             }
 
-            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
+            Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => {
                 self.check_op(ops::RawPtrToIntCast);
             }
-            Rvalue::Cast(CastKind::PointerFromExposedAddress, _, _) => {
+            Rvalue::Cast(CastKind::PointerWithExposedProvenance, _, _) => {
                 // Since no pointer can ever get exposed (rejected above), this is easy to support.
             }
 
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 378b168a50c..a499e4b980f 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -986,6 +986,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             )
                         }
                     }
+                    Cmp => {
+                        for x in [a, b] {
+                            check_kinds!(
+                                x,
+                                "Cannot three-way compare non-integer type {:?}",
+                                ty::Char | ty::Uint(..) | ty::Int(..)
+                            )
+                        }
+                    }
                     AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr
                     | ShrUnchecked => {
                         for x in [a, b] {
@@ -1067,8 +1076,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         // FIXME(dyn-star): make sure nothing needs to be done here.
                     }
                     // FIXME: Add Checks for these
-                    CastKind::PointerFromExposedAddress
-                    | CastKind::PointerExposeAddress
+                    CastKind::PointerWithExposedProvenance
+                    | CastKind::PointerExposeProvenance
                     | CastKind::PointerCoercion(_) => {}
                     CastKind::IntToInt | CastKind::IntToFloat => {
                         let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool();
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index a8060463b69..0c3b59a0e78 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -19,7 +19,7 @@ pub fn binop_left_homogeneous(op: mir::BinOp) -> bool {
     match op {
         Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
         | BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true,
-        Eq | Ne | Lt | Le | Gt | Ge => false,
+        Eq | Ne | Lt | Le | Gt | Ge | Cmp => false,
     }
 }
 
@@ -30,7 +30,7 @@ pub fn binop_right_homogeneous(op: mir::BinOp) -> bool {
     use rustc_middle::mir::BinOp::*;
     match op {
         Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
-        | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
+        | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge | Cmp => true,
         Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false,
     }
 }
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index a45f1dd72a1..30e240cf85b 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -72,7 +72,7 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
         IndexVec::with_capacity(graph.num_nodes());
 
     let mut stack = vec![PreOrderFrame {
-        pre_order_idx: PreorderIndex::new(0),
+        pre_order_idx: PreorderIndex::ZERO,
         iter: graph.successors(graph.start_node()),
     }];
     let mut pre_order_to_real: IndexVec<PreorderIndex, G::Node> =
@@ -80,8 +80,8 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
     let mut real_to_pre_order: IndexVec<G::Node, Option<PreorderIndex>> =
         IndexVec::from_elem_n(None, graph.num_nodes());
     pre_order_to_real.push(graph.start_node());
-    parent.push(PreorderIndex::new(0)); // the parent of the root node is the root for now.
-    real_to_pre_order[graph.start_node()] = Some(PreorderIndex::new(0));
+    parent.push(PreorderIndex::ZERO); // the parent of the root node is the root for now.
+    real_to_pre_order[graph.start_node()] = Some(PreorderIndex::ZERO);
     let mut post_order_idx = 0;
 
     // Traverse the graph, collecting a number of things:
@@ -111,7 +111,7 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
 
     let reachable_vertices = pre_order_to_real.len();
 
-    let mut idom = IndexVec::from_elem_n(PreorderIndex::new(0), reachable_vertices);
+    let mut idom = IndexVec::from_elem_n(PreorderIndex::ZERO, reachable_vertices);
     let mut semi = IndexVec::from_fn_n(std::convert::identity, reachable_vertices);
     let mut label = semi.clone();
     let mut bucket = IndexVec::from_elem_n(vec![], reachable_vertices);
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 15691804a94..8418b4bbd47 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -684,26 +684,11 @@ where
 impl_stable_traits_for_trivial_type!(::std::path::Path);
 impl_stable_traits_for_trivial_type!(::std::path::PathBuf);
 
-impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R>
-where
-    K: ToStableHashKey<HCX> + Eq,
-    V: HashStable<HCX>,
-    R: BuildHasher,
-{
-    #[inline]
-    fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
-        stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, (key, value)| {
-            let key = key.to_stable_hash_key(hcx);
-            key.hash_stable(hcx, hasher);
-            value.hash_stable(hcx, hasher);
-        });
-    }
-}
-
-// It is not safe to implement HashStable for HashSet or any other collection type
+// It is not safe to implement HashStable for HashSet, HashMap or any other collection type
 // with unstable but observable iteration order.
 // See https://github.com/rust-lang/compiler-team/issues/533 for further information.
 impl<V, HCX> !HashStable<HCX> for std::collections::HashSet<V> {}
+impl<K, V, HCX> !HashStable<HCX> for std::collections::HashMap<K, V> {}
 
 impl<K, V, HCX> HashStable<HCX> for ::std::collections::BTreeMap<K, V>
 where
@@ -730,35 +715,6 @@ where
     }
 }
 
-fn stable_hash_reduce<HCX, I, C, F>(
-    hcx: &mut HCX,
-    hasher: &mut StableHasher,
-    mut collection: C,
-    length: usize,
-    hash_function: F,
-) where
-    C: Iterator<Item = I>,
-    F: Fn(&mut StableHasher, &mut HCX, I),
-{
-    length.hash_stable(hcx, hasher);
-
-    match length {
-        1 => {
-            hash_function(hasher, hcx, collection.next().unwrap());
-        }
-        _ => {
-            let hash = collection
-                .map(|value| {
-                    let mut hasher = StableHasher::new();
-                    hash_function(&mut hasher, hcx, value);
-                    hasher.finish::<Hash128>()
-                })
-                .reduce(|accum, value| accum.wrapping_add(value));
-            hash.hash_stable(hcx, hasher);
-        }
-    }
-}
-
 /// Controls what data we do or do not hash.
 /// Whenever a `HashStable` implementation caches its
 /// result, it needs to include `HashingControls` as part
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
index ff4208def31..8b9e834b60b 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
@@ -243,6 +243,7 @@ where
     T: Tag,
 {
     #[inline]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn eq(&self, other: &Self) -> bool {
         self.packed == other.packed
     }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 7b40954e735..b4107bd4a2b 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -102,9 +102,9 @@ pub type PResult<'a, T> = Result<T, PErr<'a>>;
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
 
 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
@@ -1951,6 +1951,39 @@ pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
     }
 }
 
+/// Grammatical tool for displaying messages to end users in a nice form.
+///
+/// Returns "an" if the given string starts with a vowel, and "a" otherwise.
+pub fn a_or_an(s: &str) -> &'static str {
+    let mut chars = s.chars();
+    let Some(mut first_alpha_char) = chars.next() else {
+        return "a";
+    };
+    if first_alpha_char == '`' {
+        let Some(next) = chars.next() else {
+            return "a";
+        };
+        first_alpha_char = next;
+    }
+    if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
+        "an"
+    } else {
+        "a"
+    }
+}
+
+/// Grammatical tool for displaying messages to end users in a nice form.
+///
+/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
+pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
+    match v.len() {
+        0 => "".to_string(),
+        1 => v[0].to_string(),
+        2 => format!("{} and {}", v[0], v[1]),
+        _ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])),
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum TerminalUrl {
     No,
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 30559871b4e..cdcf67b26f8 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -48,6 +48,23 @@ impl<'a> ExtCtxt<'a> {
         ast::Path { span, segments, tokens: None }
     }
 
+    pub fn macro_call(
+        &self,
+        span: Span,
+        path: ast::Path,
+        delim: ast::token::Delimiter,
+        tokens: ast::tokenstream::TokenStream,
+    ) -> P<ast::MacCall> {
+        P(ast::MacCall {
+            path,
+            args: P(ast::DelimArgs {
+                dspan: ast::tokenstream::DelimSpan { open: span, close: span },
+                delim,
+                tokens,
+            }),
+        })
+    }
+
     pub fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy {
         ast::MutTy { ty, mutbl }
     }
@@ -265,6 +282,10 @@ impl<'a> ExtCtxt<'a> {
         self.expr(span, ast::ExprKind::Field(expr, field))
     }
 
+    pub fn expr_macro_call(&self, span: Span, call: P<ast::MacCall>) -> P<ast::Expr> {
+        self.expr(span, ast::ExprKind::MacCall(call))
+    }
+
     pub fn expr_binary(
         &self,
         sp: Span,
@@ -410,18 +431,21 @@ impl<'a> ExtCtxt<'a> {
         self.expr(sp, ast::ExprKind::Tup(exprs))
     }
 
-    pub fn expr_fail(&self, span: Span, msg: Symbol) -> P<ast::Expr> {
-        self.expr_call_global(
+    pub fn expr_unreachable(&self, span: Span) -> P<ast::Expr> {
+        self.expr_macro_call(
             span,
-            [sym::std, sym::rt, sym::begin_panic].iter().map(|s| Ident::new(*s, span)).collect(),
-            thin_vec![self.expr_str(span, msg)],
+            self.macro_call(
+                span,
+                self.path_global(
+                    span,
+                    [sym::std, sym::unreachable].map(|s| Ident::new(s, span)).to_vec(),
+                ),
+                ast::token::Delimiter::Parenthesis,
+                ast::tokenstream::TokenStream::default(),
+            ),
         )
     }
 
-    pub fn expr_unreachable(&self, span: Span) -> P<ast::Expr> {
-        self.expr_fail(span, Symbol::intern("internal error: entered unreachable code"))
-    }
-
     pub fn expr_ok(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
         let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]);
         self.expr_call_global(sp, ok, thin_vec![expr])
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index cac1e8f80e3..6029caa965c 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -871,7 +871,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let mut parser = self.cx.new_parser_from_tts(toks);
         match parse_ast_fragment(&mut parser, kind) {
             Ok(fragment) => {
-                ensure_complete_parse(&mut parser, path, kind.name(), span);
+                ensure_complete_parse(&parser, path, kind.name(), span);
                 fragment
             }
             Err(mut err) => {
@@ -958,7 +958,7 @@ pub fn parse_ast_fragment<'a>(
 }
 
 pub fn ensure_complete_parse<'a>(
-    parser: &mut Parser<'a>,
+    parser: &Parser<'a>,
     macro_path: &ast::Path,
     kind_name: &str,
     span: Span,
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index a31be05ccc4..9fff00ffeae 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -266,7 +266,7 @@ struct MatcherPos {
 }
 
 // This type is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(MatcherPos, 16);
 
 impl MatcherPos {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a0f86565929..f21cd653f96 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -846,9 +846,8 @@ pub struct OwnerNodes<'tcx> {
 
 impl<'tcx> OwnerNodes<'tcx> {
     pub fn node(&self) -> OwnerNode<'tcx> {
-        use rustc_index::Idx;
         // Indexing must ensure it is an OwnerNode.
-        self.nodes[ItemLocalId::new(0)].node.as_owner().unwrap()
+        self.nodes[ItemLocalId::ZERO].node.as_owner().unwrap()
     }
 }
 
@@ -856,7 +855,7 @@ impl fmt::Debug for OwnerNodes<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("OwnerNodes")
             // Do not print all the pointers to all the nodes, as it would be unreadable.
-            .field("node", &self.nodes[ItemLocalId::from_u32(0)])
+            .field("node", &self.nodes[ItemLocalId::ZERO])
             .field(
                 "parents",
                 &self
@@ -3762,7 +3761,7 @@ impl<'hir> Node<'hir> {
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     // tidy-alphabetical-start
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index d339075c171..0341a482fa8 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -17,7 +17,7 @@ impl Debug for OwnerId {
 
 impl From<OwnerId> for HirId {
     fn from(owner: OwnerId) -> HirId {
-        HirId { owner, local_id: ItemLocalId::from_u32(0) }
+        HirId { owner, local_id: ItemLocalId::ZERO }
     }
 }
 
@@ -110,7 +110,7 @@ impl HirId {
 
     #[inline]
     pub fn make_owner(owner: LocalDefId) -> Self {
-        Self { owner: OwnerId { def_id: owner }, local_id: ItemLocalId::from_u32(0) }
+        Self { owner: OwnerId { def_id: owner }, local_id: ItemLocalId::ZERO }
     }
 
     pub fn index(self) -> (usize, usize) {
@@ -172,6 +172,6 @@ unsafe impl StableOrd for ItemLocalId {
 
 /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
 pub const CRATE_HIR_ID: HirId =
-    HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::from_u32(0) };
+    HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::ZERO };
 
 pub const CRATE_OWNER_ID: OwnerId = OwnerId { def_id: CRATE_DEF_ID };
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index da592768570..2a796ca5465 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -226,6 +226,7 @@ language_item_table! {
     Unpin,                   sym::unpin,               unpin_trait,                Target::Trait,          GenericRequirement::None;
     Pin,                     sym::pin,                 pin_type,                   Target::Struct,         GenericRequirement::None;
 
+    OrderingEnum,            sym::Ordering,            ordering_enum,              Target::Enum,           GenericRequirement::Exact(0);
     PartialEq,               sym::eq,                  eq_trait,                   Target::Trait,          GenericRequirement::Exact(1);
     PartialOrd,              sym::partial_ord,         partial_ord_trait,          Target::Trait,          GenericRequirement::Exact(1);
     CVoid,                   sym::c_void,              c_void,                     Target::Enum,           GenericRequirement::None;
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 9bf4d63267a..d8a90d62dac 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -295,6 +295,8 @@ hir_analysis_not_supported_delegation =
     {$descr} is not supported yet
     .label = callee defined here
 
+hir_analysis_only_current_traits_adt = `{$name}` is not defined in the current crate
+
 hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
 
 hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index d5465bb5dd5..d3f51195dfb 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -54,14 +54,20 @@ impl<'tcx> Bounds<'tcx> {
         span: Span,
         polarity: ty::PredicatePolarity,
     ) {
-        self.clauses.push((
+        let clause = (
             trait_ref
                 .map_bound(|trait_ref| {
                     ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
                 })
                 .to_predicate(tcx),
             span,
-        ));
+        );
+        // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
+        if tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
+            self.clauses.insert(0, clause);
+        } else {
+            self.clauses.push(clause);
+        }
     }
 
     pub fn push_projection_bound(
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 1286a724e95..739a7086992 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -899,7 +899,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
             struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
             return;
         }
-        let e = fields[FieldIdx::from_u32(0)].ty(tcx, args);
+        let e = fields[FieldIdx::ZERO].ty(tcx, args);
         if !fields.iter().all(|f| f.ty(tcx, args) == e) {
             struct_span_code_err!(tcx.dcx(), sp, E0076, "SIMD vector should be homogeneous")
                 .with_span_label(sp, "SIMD elements must have the same type")
@@ -964,7 +964,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
             for r in attr::parse_repr_attr(tcx.sess, attr) {
                 if let attr::ReprPacked(pack) = r
                     && let Some(repr_pack) = repr.pack
-                    && pack as u64 != repr_pack.bytes()
+                    && pack != repr_pack
                 {
                     struct_span_code_err!(
                         tcx.dcx(),
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index f482ae4f5fa..bd64621f077 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -107,6 +107,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::cttz
         | sym::bswap
         | sym::bitreverse
+        | sym::three_way_compare
         | sym::discriminant_value
         | sym::type_id
         | sym::likely
@@ -182,7 +183,7 @@ pub fn check_intrinsic_type(
             let region = ty::Region::new_bound(
                 tcx,
                 ty::INNERMOST,
-                ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon },
+                ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon },
             );
             let env_region = ty::Region::new_bound(
                 tcx,
@@ -418,6 +419,10 @@ pub fn check_intrinsic_type(
             | sym::bswap
             | sym::bitreverse => (1, 0, vec![param(0)], param(0)),
 
+            sym::three_way_compare => {
+                (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(Some(span)))
+            }
+
             sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
                 (1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool]))
             }
@@ -454,9 +459,8 @@ pub fn check_intrinsic_type(
             sym::unchecked_div | sym::unchecked_rem | sym::exact_div => {
                 (1, 0, vec![param(0), param(0)], param(0))
             }
-            sym::unchecked_shl | sym::unchecked_shr | sym::rotate_left | sym::rotate_right => {
-                (1, 0, vec![param(0), param(0)], param(0))
-            }
+            sym::unchecked_shl | sym::unchecked_shr => (2, 0, vec![param(0), param(1)], param(0)),
+            sym::rotate_left | sym::rotate_right => (1, 0, vec![param(0), param(0)], param(0)),
             sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => {
                 (1, 0, vec![param(0), param(0)], param(0))
             }
@@ -491,7 +495,7 @@ pub fn check_intrinsic_type(
                 );
                 let discriminant_def_id = assoc_items[0];
 
-                let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon };
+                let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon };
                 (
                     1,
                     0,
@@ -551,7 +555,7 @@ pub fn check_intrinsic_type(
             }
 
             sym::raw_eq => {
-                let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon };
+                let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon };
                 let param_ty_lhs =
                     Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0));
                 let br = ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon };
@@ -623,8 +627,8 @@ pub fn check_intrinsic_type(
             sym::simd_cast
             | sym::simd_as
             | sym::simd_cast_ptr
-            | sym::simd_expose_addr
-            | sym::simd_from_exposed_addr => (2, 0, vec![param(0)], param(1)),
+            | sym::simd_expose_provenance
+            | sym::simd_with_exposed_provenance => (2, 0, vec![param(0)], param(1)),
             sym::simd_bitmask => (2, 0, vec![param(0)], param(1)),
             sym::simd_select | sym::simd_select_bitmask => {
                 (2, 0, vec![param(0), param(1), param(1)], param(1))
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index df4db3ec3fb..1958a80d47c 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -67,7 +67,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
             ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize),
             ty::Adt(adt, args) if adt.repr().simd() => {
                 let fields = &adt.non_enum_variant().fields;
-                let elem_ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, args);
+                let elem_ty = fields[FieldIdx::ZERO].ty(self.tcx, args);
 
                 let (size, ty) = match elem_ty.kind() {
                     ty::Array(ty, len) => {
@@ -146,7 +146,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     "expected first field of `MaybeUnit` to be `ManuallyDrop`"
                 );
                 let fields = &ty.non_enum_variant().fields;
-                let ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, args);
+                let ty = fields[FieldIdx::ZERO].ty(self.tcx, args);
                 self.get_asm_ty(ty)
             }
             _ => self.get_asm_ty(ty),
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index ca8a635ab5e..1770f7b4e91 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -4,7 +4,7 @@
 use crate::errors;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
-use rustc_middle::ty::{self, AliasKind, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, AliasKind, TyCtxt, TypeVisitableExt};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
 use rustc_trait_selection::traits::{self, IsFirstInputType};
@@ -283,9 +283,14 @@ fn emit_orphan_check_error<'tcx>(
     let self_ty = trait_ref.self_ty();
     Err(match err {
         traits::OrphanCheckErr::NonLocalInputType(tys) => {
-            let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) =
-                (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
-            let mut sugg = None;
+            let mut diag = tcx.dcx().create_err(match self_ty.kind() {
+                ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span: sp, note: () },
+                _ if self_ty.is_primitive() => {
+                    errors::OnlyCurrentTraits::Primitive { span: sp, note: () }
+                }
+                _ => errors::OnlyCurrentTraits::Arbitrary { span: sp, note: () },
+            });
+
             for &(mut ty, is_target_ty) in &tys {
                 let span = if matches!(is_target_ty, IsFirstInputType::Yes) {
                     // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
@@ -296,113 +301,86 @@ fn emit_orphan_check_error<'tcx>(
                 };
 
                 ty = tcx.erase_regions(ty);
-                ty = match ty.kind() {
-                    // Remove the type arguments from the output, as they are not relevant.
-                    // You can think of this as the reverse of `resolve_vars_if_possible`.
-                    // That way if we had `Vec<MyType>`, we will properly attribute the
-                    // problem to `Vec<T>` and avoid confusing the user if they were to see
-                    // `MyType` in the error.
-                    ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()),
-                    _ => ty,
-                };
-
-                fn push_to_foreign_or_name<'tcx>(
-                    is_foreign: bool,
-                    foreign: &mut Vec<errors::OnlyCurrentTraitsForeign>,
-                    name: &mut Vec<errors::OnlyCurrentTraitsName<'tcx>>,
-                    span: Span,
-                    sname: &'tcx str,
-                ) {
-                    if is_foreign {
-                        foreign.push(errors::OnlyCurrentTraitsForeign { span })
-                    } else {
-                        name.push(errors::OnlyCurrentTraitsName { span, name: sname });
-                    }
-                }
 
                 let is_foreign =
                     !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
 
                 match *ty.kind() {
                     ty::Slice(_) => {
-                        push_to_foreign_or_name(
-                            is_foreign,
-                            &mut foreign,
-                            &mut name,
-                            span,
-                            "slices",
-                        );
+                        if is_foreign {
+                            diag.subdiagnostic(
+                                tcx.dcx(),
+                                errors::OnlyCurrentTraitsForeign { span },
+                            );
+                        } else {
+                            diag.subdiagnostic(
+                                tcx.dcx(),
+                                errors::OnlyCurrentTraitsName { span, name: "slices" },
+                            );
+                        }
                     }
                     ty::Array(..) => {
-                        push_to_foreign_or_name(
-                            is_foreign,
-                            &mut foreign,
-                            &mut name,
-                            span,
-                            "arrays",
-                        );
+                        if is_foreign {
+                            diag.subdiagnostic(
+                                tcx.dcx(),
+                                errors::OnlyCurrentTraitsForeign { span },
+                            );
+                        } else {
+                            diag.subdiagnostic(
+                                tcx.dcx(),
+                                errors::OnlyCurrentTraitsName { span, name: "arrays" },
+                            );
+                        }
                     }
                     ty::Tuple(..) => {
-                        push_to_foreign_or_name(
-                            is_foreign,
-                            &mut foreign,
-                            &mut name,
-                            span,
-                            "tuples",
-                        );
+                        if is_foreign {
+                            diag.subdiagnostic(
+                                tcx.dcx(),
+                                errors::OnlyCurrentTraitsForeign { span },
+                            );
+                        } else {
+                            diag.subdiagnostic(
+                                tcx.dcx(),
+                                errors::OnlyCurrentTraitsName { span, name: "tuples" },
+                            );
+                        }
                     }
                     ty::Alias(ty::Opaque, ..) => {
-                        opaque.push(errors::OnlyCurrentTraitsOpaque { span })
+                        diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span });
                     }
                     ty::RawPtr(ptr_ty, mutbl) => {
                         if !self_ty.has_param() {
-                            let mut_key = mutbl.prefix_str();
-                            sugg = Some(errors::OnlyCurrentTraitsPointerSugg {
-                                wrapper_span: self_ty_span,
-                                struct_span: full_impl_span.shrink_to_lo(),
-                                mut_key,
-                                ptr_ty,
-                            });
+                            diag.subdiagnostic(
+                                tcx.dcx(),
+                                errors::OnlyCurrentTraitsPointerSugg {
+                                    wrapper_span: self_ty_span,
+                                    struct_span: full_impl_span.shrink_to_lo(),
+                                    mut_key: mutbl.prefix_str(),
+                                    ptr_ty,
+                                },
+                            );
                         }
-                        pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
+                        diag.subdiagnostic(
+                            tcx.dcx(),
+                            errors::OnlyCurrentTraitsPointer { span, pointer: ty },
+                        );
+                    }
+                    ty::Adt(adt_def, _) => {
+                        diag.subdiagnostic(
+                            tcx.dcx(),
+                            errors::OnlyCurrentTraitsAdt {
+                                span,
+                                name: tcx.def_path_str(adt_def.did()),
+                            },
+                        );
+                    }
+                    _ => {
+                        diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsTy { span, ty });
                     }
-                    _ => ty_diag.push(errors::OnlyCurrentTraitsTy { span, ty }),
                 }
             }
 
-            let err_struct = match self_ty.kind() {
-                ty::Adt(..) => errors::OnlyCurrentTraits::Outside {
-                    span: sp,
-                    note: (),
-                    opaque,
-                    foreign,
-                    name,
-                    pointer,
-                    ty: ty_diag,
-                    sugg,
-                },
-                _ if self_ty.is_primitive() => errors::OnlyCurrentTraits::Primitive {
-                    span: sp,
-                    note: (),
-                    opaque,
-                    foreign,
-                    name,
-                    pointer,
-                    ty: ty_diag,
-                    sugg,
-                },
-                _ => errors::OnlyCurrentTraits::Arbitrary {
-                    span: sp,
-                    note: (),
-                    opaque,
-                    foreign,
-                    name,
-                    pointer,
-                    ty: ty_diag,
-                    sugg,
-                },
-            };
-            tcx.dcx().emit_err(err_struct)
+            diag.emit()
         }
         traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
             let mut sp = sp;
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 ee3436805ca..0b8ac9926e4 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -418,8 +418,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
         {
             if let &hir::ClosureBinder::For { span: for_sp, .. } = binder {
                 fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> {
-                    struct V;
-                    impl<'v> Visitor<'v> for V {
+                    /// Look for `_` anywhere in the signature of a `for<> ||` closure.
+                    /// This is currently disallowed.
+                    struct FindInferInClosureWithBinder;
+                    impl<'v> Visitor<'v> for FindInferInClosureWithBinder {
                         type Result = ControlFlow<Span>;
                         fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> Self::Result {
                             if matches!(t.kind, hir::TyKind::Infer) {
@@ -429,7 +431,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                             }
                         }
                     }
-                    V.visit_ty(ty).break_value()
+                    FindInferInClosureWithBinder.visit_ty(ty).break_value()
                 }
 
                 let infer_in_rt_sp = match fn_decl.output {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 722def2563c..9d7deebac48 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -474,9 +474,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             VariantData::Unit(..) | VariantData::Struct { .. } => {
                 tcx.type_of(tcx.hir().get_parent_item(hir_id)).instantiate_identity()
             }
-            VariantData::Tuple(..) => {
+            VariantData::Tuple(_, _, ctor) => {
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
-                Ty::new_fn_def(tcx, def_id.to_def_id(), args)
+                Ty::new_fn_def(tcx, ctor.to_def_id(), args)
             }
         },
 
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index fb919714afd..2d4742fa1dc 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1376,7 +1376,7 @@ pub struct TyParamSome<'a> {
 }
 
 #[derive(Diagnostic)]
-pub enum OnlyCurrentTraits<'a> {
+pub enum OnlyCurrentTraits {
     #[diag(hir_analysis_only_current_traits_outside, code = E0117)]
     Outside {
         #[primary_span]
@@ -1384,18 +1384,6 @@ pub enum OnlyCurrentTraits<'a> {
         span: Span,
         #[note(hir_analysis_only_current_traits_note)]
         note: (),
-        #[subdiagnostic]
-        opaque: Vec<OnlyCurrentTraitsOpaque>,
-        #[subdiagnostic]
-        foreign: Vec<OnlyCurrentTraitsForeign>,
-        #[subdiagnostic]
-        name: Vec<OnlyCurrentTraitsName<'a>>,
-        #[subdiagnostic]
-        pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
-        #[subdiagnostic]
-        ty: Vec<OnlyCurrentTraitsTy<'a>>,
-        #[subdiagnostic]
-        sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
     },
     #[diag(hir_analysis_only_current_traits_primitive, code = E0117)]
     Primitive {
@@ -1404,18 +1392,6 @@ pub enum OnlyCurrentTraits<'a> {
         span: Span,
         #[note(hir_analysis_only_current_traits_note)]
         note: (),
-        #[subdiagnostic]
-        opaque: Vec<OnlyCurrentTraitsOpaque>,
-        #[subdiagnostic]
-        foreign: Vec<OnlyCurrentTraitsForeign>,
-        #[subdiagnostic]
-        name: Vec<OnlyCurrentTraitsName<'a>>,
-        #[subdiagnostic]
-        pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
-        #[subdiagnostic]
-        ty: Vec<OnlyCurrentTraitsTy<'a>>,
-        #[subdiagnostic]
-        sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
     },
     #[diag(hir_analysis_only_current_traits_arbitrary, code = E0117)]
     Arbitrary {
@@ -1424,18 +1400,6 @@ pub enum OnlyCurrentTraits<'a> {
         span: Span,
         #[note(hir_analysis_only_current_traits_note)]
         note: (),
-        #[subdiagnostic]
-        opaque: Vec<OnlyCurrentTraitsOpaque>,
-        #[subdiagnostic]
-        foreign: Vec<OnlyCurrentTraitsForeign>,
-        #[subdiagnostic]
-        name: Vec<OnlyCurrentTraitsName<'a>>,
-        #[subdiagnostic]
-        pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
-        #[subdiagnostic]
-        ty: Vec<OnlyCurrentTraitsTy<'a>>,
-        #[subdiagnostic]
-        sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
     },
 }
 
@@ -1445,7 +1409,6 @@ pub struct OnlyCurrentTraitsOpaque {
     #[primary_span]
     pub span: Span,
 }
-
 #[derive(Subdiagnostic)]
 #[label(hir_analysis_only_current_traits_foreign)]
 pub struct OnlyCurrentTraitsForeign {
@@ -1478,6 +1441,14 @@ pub struct OnlyCurrentTraitsTy<'a> {
 }
 
 #[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_adt)]
+pub struct OnlyCurrentTraitsAdt {
+    #[primary_span]
+    pub span: Span,
+    pub name: String,
+}
+
+#[derive(Subdiagnostic)]
 #[multipart_suggestion(
     hir_analysis_only_current_traits_pointer_sugg,
     applicability = "maybe-incorrect"
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 ca2e14ee359..70f09dd6175 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -1,6 +1,6 @@
 use crate::errors::{
     self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
-    ParenthesizedFnTraitExpansion,
+    ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
 };
 use crate::fluent_generated as fluent;
 use crate::hir_ty_lowering::HirTyLowerer;
@@ -8,19 +8,26 @@ use crate::traits::error_reporting::report_object_safety_error;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordMap;
+use rustc_errors::MultiSpan;
 use rustc_errors::{
     codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
 };
 use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::traits::FulfillmentError;
 use rustc_middle::query::Key;
-use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, suggest_constraining_type_param};
+use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{Binder, TraitRef};
 use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::find_best_match_for_name;
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::BytePos;
 use rustc_span::{Span, Symbol, DUMMY_SP};
-use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
+use rustc_trait_selection::traits::{
+    object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
+};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
@@ -621,7 +628,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     let projection_ty = pred.skip_binder().projection_ty;
 
                     let args_with_infer_self = tcx.mk_args_from_iter(
-                        std::iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into())
+                        std::iter::once(Ty::new_var(tcx, ty::TyVid::ZERO).into())
                             .chain(projection_ty.args.iter().skip(1)),
                     );
 
@@ -1024,6 +1031,170 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             Ok(())
         }
     }
+
+    pub fn report_prohibit_generics_error<'a>(
+        &self,
+        segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
+        args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
+        err_extend: GenericsArgsErrExtend<'_>,
+    ) -> ErrorGuaranteed {
+        #[derive(PartialEq, Eq, Hash)]
+        enum ProhibitGenericsArg {
+            Lifetime,
+            Type,
+            Const,
+            Infer,
+        }
+
+        let mut prohibit_args = FxIndexSet::default();
+        args_visitors.for_each(|arg| {
+            match arg {
+                hir::GenericArg::Lifetime(_) => prohibit_args.insert(ProhibitGenericsArg::Lifetime),
+                hir::GenericArg::Type(_) => prohibit_args.insert(ProhibitGenericsArg::Type),
+                hir::GenericArg::Const(_) => prohibit_args.insert(ProhibitGenericsArg::Const),
+                hir::GenericArg::Infer(_) => prohibit_args.insert(ProhibitGenericsArg::Infer),
+            };
+        });
+
+        let types_and_spans: Vec<_> = segments
+            .clone()
+            .flat_map(|segment| {
+                if segment.args().args.is_empty() {
+                    None
+                } else {
+                    Some((
+                        match segment.res {
+                            hir::def::Res::PrimTy(ty) => {
+                                format!("{} `{}`", segment.res.descr(), ty.name())
+                            }
+                            hir::def::Res::Def(_, def_id)
+                                if let Some(name) = self.tcx().opt_item_name(def_id) =>
+                            {
+                                format!("{} `{name}`", segment.res.descr())
+                            }
+                            hir::def::Res::Err => "this type".to_string(),
+                            _ => segment.res.descr().to_string(),
+                        },
+                        segment.ident.span,
+                    ))
+                }
+            })
+            .collect();
+        let this_type = match &types_and_spans[..] {
+            [.., _, (last, _)] => format!(
+                "{} and {last}",
+                types_and_spans[..types_and_spans.len() - 1]
+                    .iter()
+                    .map(|(x, _)| x.as_str())
+                    .intersperse(", ")
+                    .collect::<String>()
+            ),
+            [(only, _)] => only.to_string(),
+            [] => "this type".to_string(),
+        };
+
+        let arg_spans: Vec<Span> = segments
+            .clone()
+            .flat_map(|segment| segment.args().args)
+            .map(|arg| arg.span())
+            .collect();
+
+        let mut kinds = Vec::with_capacity(4);
+        prohibit_args.iter().for_each(|arg| match arg {
+            ProhibitGenericsArg::Lifetime => kinds.push("lifetime"),
+            ProhibitGenericsArg::Type => kinds.push("type"),
+            ProhibitGenericsArg::Const => kinds.push("const"),
+            ProhibitGenericsArg::Infer => kinds.push("generic"),
+        });
+
+        let (kind, s) = match kinds[..] {
+            [.., _, last] => (
+                format!(
+                    "{} and {last}",
+                    kinds[..kinds.len() - 1]
+                        .iter()
+                        .map(|&x| x)
+                        .intersperse(", ")
+                        .collect::<String>()
+                ),
+                "s",
+            ),
+            [only] => (only.to_string(), ""),
+            [] => unreachable!("expected at least one generic to prohibit"),
+        };
+        let last_span = *arg_spans.last().unwrap();
+        let span: MultiSpan = arg_spans.into();
+        let mut err = struct_span_code_err!(
+            self.tcx().dcx(),
+            span,
+            E0109,
+            "{kind} arguments are not allowed on {this_type}",
+        );
+        err.span_label(last_span, format!("{kind} argument{s} not allowed"));
+        for (what, span) in types_and_spans {
+            err.span_label(span, format!("not allowed on {what}"));
+        }
+        generics_args_err_extend(self.tcx(), segments.clone(), &mut err, err_extend);
+        let reported = err.emit();
+        self.set_tainted_by_errors(reported);
+        reported
+    }
+
+    pub fn report_trait_object_addition_traits_error(
+        &self,
+        regular_traits: &Vec<TraitAliasExpansionInfo<'_>>,
+    ) -> ErrorGuaranteed {
+        let tcx = self.tcx();
+        let first_trait = &regular_traits[0];
+        let additional_trait = &regular_traits[1];
+        let mut err = struct_span_code_err!(
+            tcx.dcx(),
+            additional_trait.bottom().1,
+            E0225,
+            "only auto traits can be used as additional traits in a trait object"
+        );
+        additional_trait.label_with_exp_info(
+            &mut err,
+            "additional non-auto trait",
+            "additional use",
+        );
+        first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
+        err.help(format!(
+            "consider creating a new trait with all of these as supertraits and using that \
+             trait here instead: `trait NewTrait: {} {{}}`",
+            regular_traits
+                .iter()
+                // FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
+                .map(|t| t.trait_ref().print_only_trait_path().to_string())
+                .collect::<Vec<_>>()
+                .join(" + "),
+        ));
+        err.note(
+            "auto-traits like `Send` and `Sync` are traits that have special properties; \
+             for more information on them, visit \
+             <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
+        );
+        let reported = err.emit();
+        self.set_tainted_by_errors(reported);
+        reported
+    }
+
+    pub fn report_trait_object_with_no_traits_error(
+        &self,
+        span: Span,
+        trait_bounds: &Vec<(Binder<'tcx, TraitRef<'tcx>>, Span)>,
+    ) -> ErrorGuaranteed {
+        let tcx = self.tcx();
+        let trait_alias_span = trait_bounds
+            .iter()
+            .map(|&(trait_ref, _)| trait_ref.def_id())
+            .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
+            .map(|trait_ref| tcx.def_span(trait_ref));
+        let reported =
+            tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
+        self.set_tainted_by_errors(reported);
+        reported
+    }
 }
 
 /// Emits an error regarding forbidden type binding associations
@@ -1031,7 +1202,7 @@ pub fn prohibit_assoc_item_binding(
     tcx: TyCtxt<'_>,
     span: Span,
     segment: Option<(&hir::PathSegment<'_>, Span)>,
-) {
+) -> ErrorGuaranteed {
     tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
         span,
         fn_trait_expansion: if let Some((segment, span)) = segment
@@ -1044,7 +1215,7 @@ pub fn prohibit_assoc_item_binding(
         } else {
             None
         },
-    });
+    })
 }
 
 pub(crate) fn fn_trait_to_string(
@@ -1099,3 +1270,208 @@ pub(crate) fn fn_trait_to_string(
         format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
     }
 }
+
+/// Used for generics args error extend.
+pub enum GenericsArgsErrExtend<'tcx> {
+    EnumVariant {
+        qself: &'tcx hir::Ty<'tcx>,
+        assoc_segment: &'tcx hir::PathSegment<'tcx>,
+        adt_def: AdtDef<'tcx>,
+    },
+    OpaqueTy,
+    PrimTy(hir::PrimTy),
+    SelfTyAlias {
+        def_id: DefId,
+        span: Span,
+    },
+    SelfTyParam(Span),
+    TyParam(DefId),
+    DefVariant,
+    None,
+}
+
+fn generics_args_err_extend<'a>(
+    tcx: TyCtxt<'_>,
+    segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
+    err: &mut Diag<'_>,
+    err_extend: GenericsArgsErrExtend<'_>,
+) {
+    match err_extend {
+        GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => {
+            err.note("enum variants can't have type parameters");
+            let type_name = tcx.item_name(adt_def.did());
+            let msg = format!(
+                "you might have meant to specify type parameters on enum \
+                `{type_name}`"
+            );
+            let Some(args) = assoc_segment.args else {
+                return;
+            };
+            // Get the span of the generics args *including* the leading `::`.
+            // We do so by stretching args.span_ext to the left by 2. Earlier
+            // it was done based on the end of assoc segment but that sometimes
+            // led to impossible spans and caused issues like #116473
+            let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
+            if tcx.generics_of(adt_def.did()).count() == 0 {
+                // FIXME(estebank): we could also verify that the arguments being
+                // work for the `enum`, instead of just looking if it takes *any*.
+                err.span_suggestion_verbose(
+                    args_span,
+                    format!("{type_name} doesn't have generic parameters"),
+                    "",
+                    Applicability::MachineApplicable,
+                );
+                return;
+            }
+            let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
+                err.note(msg);
+                return;
+            };
+            let (qself_sugg_span, is_self) =
+                if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
+                    // If the path segment already has type params, we want to overwrite
+                    // them.
+                    match &path.segments {
+                        // `segment` is the previous to last element on the path,
+                        // which would normally be the `enum` itself, while the last
+                        // `_` `PathSegment` corresponds to the variant.
+                        [
+                            ..,
+                            hir::PathSegment {
+                                ident, args, res: Res::Def(DefKind::Enum, _), ..
+                            },
+                            _,
+                        ] => (
+                            // We need to include the `::` in `Type::Variant::<Args>`
+                            // to point the span to `::<Args>`, not just `<Args>`.
+                            ident
+                                .span
+                                .shrink_to_hi()
+                                .to(args.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
+                            false,
+                        ),
+                        [segment] => {
+                            (
+                                // We need to include the `::` in `Type::Variant::<Args>`
+                                // to point the span to `::<Args>`, not just `<Args>`.
+                                segment.ident.span.shrink_to_hi().to(segment
+                                    .args
+                                    .map_or(segment.ident.span.shrink_to_hi(), |a| a.span_ext)),
+                                kw::SelfUpper == segment.ident.name,
+                            )
+                        }
+                        _ => {
+                            err.note(msg);
+                            return;
+                        }
+                    }
+                } else {
+                    err.note(msg);
+                    return;
+                };
+            let suggestion = vec![
+                if is_self {
+                    // Account for people writing `Self::Variant::<Args>`, where
+                    // `Self` is the enum, and suggest replacing `Self` with the
+                    // appropriate type: `Type::<Args>::Variant`.
+                    (qself.span, format!("{type_name}{snippet}"))
+                } else {
+                    (qself_sugg_span, snippet)
+                },
+                (args_span, String::new()),
+            ];
+            err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect);
+        }
+        GenericsArgsErrExtend::PrimTy(prim_ty) => {
+            let name = prim_ty.name_str();
+            for segment in segments {
+                if let Some(args) = segment.args {
+                    err.span_suggestion_verbose(
+                        segment.ident.span.shrink_to_hi().to(args.span_ext),
+                        format!("primitive type `{name}` doesn't have generic parameters"),
+                        "",
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+        GenericsArgsErrExtend::OpaqueTy => {
+            err.note("`impl Trait` types can't have type parameters");
+        }
+        GenericsArgsErrExtend::DefVariant => {
+            err.note("enum variants can't have type parameters");
+        }
+        GenericsArgsErrExtend::TyParam(def_id) => {
+            if let Some(span) = tcx.def_ident_span(def_id) {
+                let name = tcx.item_name(def_id);
+                err.span_note(span, format!("type parameter `{name}` defined here"));
+            }
+        }
+        GenericsArgsErrExtend::SelfTyParam(span) => {
+            err.span_suggestion_verbose(
+                span,
+                "the `Self` type doesn't accept type parameters",
+                "",
+                Applicability::MaybeIncorrect,
+            );
+        }
+        GenericsArgsErrExtend::SelfTyAlias { def_id, span } => {
+            let ty = tcx.at(span).type_of(def_id).instantiate_identity();
+            let span_of_impl = tcx.span_of_impl(def_id);
+            let def_id = match *ty.kind() {
+                ty::Adt(self_def, _) => self_def.did(),
+                _ => return,
+            };
+
+            let type_name = tcx.item_name(def_id);
+            let span_of_ty = tcx.def_ident_span(def_id);
+            let generics = tcx.generics_of(def_id).count();
+
+            let msg = format!("`Self` is of type `{ty}`");
+            if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
+                let mut span: MultiSpan = vec![t_sp].into();
+                span.push_span_label(
+                    i_sp,
+                    format!("`Self` is on type `{type_name}` in this `impl`"),
+                );
+                let mut postfix = "";
+                if generics == 0 {
+                    postfix = ", which doesn't have generic parameters";
+                }
+                span.push_span_label(t_sp, format!("`Self` corresponds to this type{postfix}"));
+                err.span_note(span, msg);
+            } else {
+                err.note(msg);
+            }
+            for segment in segments {
+                if let Some(args) = segment.args
+                    && segment.ident.name == kw::SelfUpper
+                {
+                    if generics == 0 {
+                        // FIXME(estebank): we could also verify that the arguments being
+                        // work for the `enum`, instead of just looking if it takes *any*.
+                        err.span_suggestion_verbose(
+                            segment.ident.span.shrink_to_hi().to(args.span_ext),
+                            "the `Self` type doesn't accept type parameters",
+                            "",
+                            Applicability::MachineApplicable,
+                        );
+                        return;
+                    } else {
+                        err.span_suggestion_verbose(
+                            segment.ident.span,
+                            format!(
+                                "the `Self` type doesn't accept type parameters, use the \
+                                concrete type's name `{type_name}` instead if you want to \
+                                specify its type parameters"
+                            ),
+                            type_name,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+        }
+        _ => {}
+    }
+}
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 8886a78c6ec..f726f2a7b89 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -14,7 +14,7 @@
 //! trait references and bounds.
 
 mod bounds;
-mod errors;
+pub mod errors;
 pub mod generics;
 mod lint;
 mod object_safety;
@@ -22,14 +22,14 @@ mod object_safety;
 use crate::bounds::Bounds;
 use crate::collect::HirPlaceholderCollector;
 use crate::errors::AmbiguousLifetimeBound;
-use crate::hir_ty_lowering::errors::prohibit_assoc_item_binding;
+use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
 use crate::middle::resolve_bound_vars as rbv;
 use crate::require_c_abi_if_c_variadic;
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::{
-    codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError, MultiSpan,
+    codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@@ -46,7 +46,7 @@ use rustc_middle::ty::{
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{sym, BytePos, Span, DUMMY_SP};
+use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
@@ -632,7 +632,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         trait_ref: &hir::TraitRef<'tcx>,
         self_ty: Ty<'tcx>,
     ) -> ty::TraitRef<'tcx> {
-        self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
+        let _ = self.prohibit_generic_args(
+            trait_ref.path.segments.split_last().unwrap().1.iter(),
+            GenericsArgsErrExtend::None,
+        );
 
         self.lower_mono_trait_ref(
             trait_ref.path.span,
@@ -681,7 +684,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
         let trait_segment = trait_ref.path.segments.last().unwrap();
 
-        self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
+        let _ = self.prohibit_generic_args(
+            trait_ref.path.segments.split_last().unwrap().1.iter(),
+            GenericsArgsErrExtend::None,
+        );
         self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
 
         let (generic_args, arg_count) = self.lower_generic_args_of_path(
@@ -995,8 +1001,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         hir_ref_id: hir::HirId,
         span: Span,
         qself_ty: Ty<'tcx>,
-        qself: &hir::Ty<'_>,
-        assoc_segment: &hir::PathSegment<'tcx>,
+        qself: &'tcx hir::Ty<'tcx>,
+        assoc_segment: &'tcx hir::PathSegment<'tcx>,
         permit_variants: bool,
     ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
         debug!(%qself_ty, ?assoc_segment.ident);
@@ -1020,99 +1026,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 if let Some(variant_def) = variant_def {
                     if permit_variants {
                         tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
-                        self.prohibit_generic_args(slice::from_ref(assoc_segment).iter(), |err| {
-                            err.note("enum variants can't have type parameters");
-                            let type_name = tcx.item_name(adt_def.did());
-                            let msg = format!(
-                                "you might have meant to specify type parameters on enum \
-                                 `{type_name}`"
-                            );
-                            let Some(args) = assoc_segment.args else {
-                                return;
-                            };
-                            // Get the span of the generics args *including* the leading `::`.
-                            // We do so by stretching args.span_ext to the left by 2. Earlier
-                            // it was done based on the end of assoc segment but that sometimes
-                            // led to impossible spans and caused issues like #116473
-                            let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
-                            if tcx.generics_of(adt_def.did()).count() == 0 {
-                                // FIXME(estebank): we could also verify that the arguments being
-                                // work for the `enum`, instead of just looking if it takes *any*.
-                                err.span_suggestion_verbose(
-                                    args_span,
-                                    format!("{type_name} doesn't have generic parameters"),
-                                    "",
-                                    Applicability::MachineApplicable,
-                                );
-                                return;
-                            }
-                            let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span)
-                            else {
-                                err.note(msg);
-                                return;
-                            };
-                            let (qself_sugg_span, is_self) =
-                                if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) =
-                                    &qself.kind
-                                {
-                                    // If the path segment already has type params, we want to overwrite
-                                    // them.
-                                    match &path.segments {
-                                        // `segment` is the previous to last element on the path,
-                                        // which would normally be the `enum` itself, while the last
-                                        // `_` `PathSegment` corresponds to the variant.
-                                        [
-                                            ..,
-                                            hir::PathSegment {
-                                                ident,
-                                                args,
-                                                res: Res::Def(DefKind::Enum, _),
-                                                ..
-                                            },
-                                            _,
-                                        ] => (
-                                            // We need to include the `::` in `Type::Variant::<Args>`
-                                            // to point the span to `::<Args>`, not just `<Args>`.
-                                            ident.span.shrink_to_hi().to(args
-                                                .map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
-                                            false,
-                                        ),
-                                        [segment] => (
-                                            // We need to include the `::` in `Type::Variant::<Args>`
-                                            // to point the span to `::<Args>`, not just `<Args>`.
-                                            segment.ident.span.shrink_to_hi().to(segment
-                                                .args
-                                                .map_or(segment.ident.span.shrink_to_hi(), |a| {
-                                                    a.span_ext
-                                                })),
-                                            kw::SelfUpper == segment.ident.name,
-                                        ),
-                                        _ => {
-                                            err.note(msg);
-                                            return;
-                                        }
-                                    }
-                                } else {
-                                    err.note(msg);
-                                    return;
-                                };
-                            let suggestion = vec![
-                                if is_self {
-                                    // Account for people writing `Self::Variant::<Args>`, where
-                                    // `Self` is the enum, and suggest replacing `Self` with the
-                                    // appropriate type: `Type::<Args>::Variant`.
-                                    (qself.span, format!("{type_name}{snippet}"))
-                                } else {
-                                    (qself_sugg_span, snippet)
-                                },
-                                (args_span, String::new()),
-                            ];
-                            err.multipart_suggestion_verbose(
-                                msg,
-                                suggestion,
-                                Applicability::MaybeIncorrect,
-                            );
-                        });
+                        let _ = self.prohibit_generic_args(
+                            slice::from_ref(assoc_segment).iter(),
+                            GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
+                        );
                         return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
                     } else {
                         variant_resolution = Some(variant_def.def_id);
@@ -1624,111 +1541,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     pub fn prohibit_generic_args<'a>(
         &self,
         segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
-        extend: impl Fn(&mut Diag<'_>),
-    ) -> bool {
-        let args = segments.clone().flat_map(|segment| segment.args().args);
-
-        let (lt, ty, ct, inf) =
-            args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg {
-                hir::GenericArg::Lifetime(_) => (true, ty, ct, inf),
-                hir::GenericArg::Type(_) => (lt, true, ct, inf),
-                hir::GenericArg::Const(_) => (lt, ty, true, inf),
-                hir::GenericArg::Infer(_) => (lt, ty, ct, true),
-            });
-        let mut emitted = false;
-        if lt || ty || ct || inf {
-            let types_and_spans: Vec<_> = segments
-                .clone()
-                .flat_map(|segment| {
-                    if segment.args().args.is_empty() {
-                        None
-                    } else {
-                        Some((
-                            match segment.res {
-                                Res::PrimTy(ty) => {
-                                    format!("{} `{}`", segment.res.descr(), ty.name())
-                                }
-                                Res::Def(_, def_id)
-                                    if let Some(name) = self.tcx().opt_item_name(def_id) =>
-                                {
-                                    format!("{} `{name}`", segment.res.descr())
-                                }
-                                Res::Err => "this type".to_string(),
-                                _ => segment.res.descr().to_string(),
-                            },
-                            segment.ident.span,
-                        ))
-                    }
-                })
-                .collect();
-            let this_type = match &types_and_spans[..] {
-                [.., _, (last, _)] => format!(
-                    "{} and {last}",
-                    types_and_spans[..types_and_spans.len() - 1]
-                        .iter()
-                        .map(|(x, _)| x.as_str())
-                        .intersperse(", ")
-                        .collect::<String>()
-                ),
-                [(only, _)] => only.to_string(),
-                [] => "this type".to_string(),
-            };
-
-            let arg_spans: Vec<Span> = args.map(|arg| arg.span()).collect();
-
-            let mut kinds = Vec::with_capacity(4);
-            if lt {
-                kinds.push("lifetime");
-            }
-            if ty {
-                kinds.push("type");
-            }
-            if ct {
-                kinds.push("const");
-            }
-            if inf {
-                kinds.push("generic");
-            }
-            let (kind, s) = match kinds[..] {
-                [.., _, last] => (
-                    format!(
-                        "{} and {last}",
-                        kinds[..kinds.len() - 1]
-                            .iter()
-                            .map(|&x| x)
-                            .intersperse(", ")
-                            .collect::<String>()
-                    ),
-                    "s",
-                ),
-                [only] => (only.to_string(), ""),
-                [] => unreachable!("expected at least one generic to prohibit"),
-            };
-            let last_span = *arg_spans.last().unwrap();
-            let span: MultiSpan = arg_spans.into();
-            let mut err = struct_span_code_err!(
-                self.tcx().dcx(),
-                span,
-                E0109,
-                "{kind} arguments are not allowed on {this_type}",
-            );
-            err.span_label(last_span, format!("{kind} argument{s} not allowed"));
-            for (what, span) in types_and_spans {
-                err.span_label(span, format!("not allowed on {what}"));
-            }
-            extend(&mut err);
-            self.set_tainted_by_errors(err.emit());
-            emitted = true;
+        err_extend: GenericsArgsErrExtend<'_>,
+    ) -> Result<(), ErrorGuaranteed> {
+        let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
+        let mut result = Ok(());
+        if let Some(_) = args_visitors.clone().next() {
+            result = Err(self.report_prohibit_generics_error(
+                segments.clone(),
+                args_visitors,
+                err_extend,
+            ));
         }
 
         for segment in segments {
             // Only emit the first error to avoid overloading the user with error messages.
             if let Some(b) = segment.args().bindings.first() {
-                prohibit_assoc_item_binding(self.tcx(), b.span, None);
-                return true;
+                return Err(prohibit_assoc_item_binding(self.tcx(), b.span, None));
             }
         }
-        emitted
+
+        result
     }
 
     /// Probe path segments that are semantically allowed to have generic arguments.
@@ -1893,9 +1725,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // Check for desugared `impl Trait`.
                 assert!(tcx.is_type_alias_impl_trait(did));
                 let item_segment = path.segments.split_last().unwrap();
-                self.prohibit_generic_args(item_segment.1.iter(), |err| {
-                    err.note("`impl Trait` types can't have type parameters");
-                });
+                let _ = self
+                    .prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy);
                 let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0);
                 Ty::new_opaque(tcx, did, args)
             }
@@ -1908,7 +1739,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 did,
             ) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.split_last().unwrap().1.iter(), |_| {});
+                let _ = self.prohibit_generic_args(
+                    path.segments.split_last().unwrap().1.iter(),
+                    GenericsArgsErrExtend::None,
+                );
                 self.lower_path_segment(span, did, path.segments.last().unwrap())
             }
             Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
@@ -1920,13 +1754,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     self.probe_generic_path_segments(path.segments, None, kind, def_id, span);
                 let indices: FxHashSet<_> =
                     generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
-                self.prohibit_generic_args(
+                let _ = self.prohibit_generic_args(
                     path.segments.iter().enumerate().filter_map(|(index, seg)| {
                         if !indices.contains(&index) { Some(seg) } else { None }
                     }),
-                    |err| {
-                        err.note("enum variants can't have type parameters");
-                    },
+                    GenericsArgsErrExtend::DefVariant,
                 );
 
                 let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
@@ -1934,27 +1766,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
             Res::Def(DefKind::TyParam, def_id) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
-                    if let Some(span) = tcx.def_ident_span(def_id) {
-                        let name = tcx.item_name(def_id);
-                        err.span_note(span, format!("type parameter `{name}` defined here"));
-                    }
-                });
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
+                    GenericsArgsErrExtend::TyParam(def_id),
+                );
                 self.lower_ty_param(hir_id)
             }
             Res::SelfTyParam { .. } => {
                 // `Self` in trait or type alias.
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
                     if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments {
-                        err.span_suggestion_verbose(
+                        GenericsArgsErrExtend::SelfTyParam(
                             ident.span.shrink_to_hi().to(args.span_ext),
-                            "the `Self` type doesn't accept type parameters",
-                            "",
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                });
+                        )
+                    } else {
+                        GenericsArgsErrExtend::None
+                    },
+                );
                 tcx.types.self_param
             }
             Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
@@ -1962,65 +1792,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 assert_eq!(opt_self_ty, None);
                 // Try to evaluate any array length constants.
                 let ty = tcx.at(span).type_of(def_id).instantiate_identity();
-                let span_of_impl = tcx.span_of_impl(def_id);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
-                    let def_id = match *ty.kind() {
-                        ty::Adt(self_def, _) => self_def.did(),
-                        _ => return,
-                    };
-
-                    let type_name = tcx.item_name(def_id);
-                    let span_of_ty = tcx.def_ident_span(def_id);
-                    let generics = tcx.generics_of(def_id).count();
-
-                    let msg = format!("`Self` is of type `{ty}`");
-                    if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
-                        let mut span: MultiSpan = vec![t_sp].into();
-                        span.push_span_label(
-                            i_sp,
-                            format!("`Self` is on type `{type_name}` in this `impl`"),
-                        );
-                        let mut postfix = "";
-                        if generics == 0 {
-                            postfix = ", which doesn't have generic parameters";
-                        }
-                        span.push_span_label(
-                            t_sp,
-                            format!("`Self` corresponds to this type{postfix}"),
-                        );
-                        err.span_note(span, msg);
-                    } else {
-                        err.note(msg);
-                    }
-                    for segment in path.segments {
-                        if let Some(args) = segment.args
-                            && segment.ident.name == kw::SelfUpper
-                        {
-                            if generics == 0 {
-                                // FIXME(estebank): we could also verify that the arguments being
-                                // work for the `enum`, instead of just looking if it takes *any*.
-                                err.span_suggestion_verbose(
-                                    segment.ident.span.shrink_to_hi().to(args.span_ext),
-                                    "the `Self` type doesn't accept type parameters",
-                                    "",
-                                    Applicability::MachineApplicable,
-                                );
-                                return;
-                            } else {
-                                err.span_suggestion_verbose(
-                                    segment.ident.span,
-                                    format!(
-                                        "the `Self` type doesn't accept type parameters, use the \
-                                        concrete type's name `{type_name}` instead if you want to \
-                                        specify its type parameters"
-                                    ),
-                                    type_name,
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-                        }
-                    }
-                });
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
+                    GenericsArgsErrExtend::SelfTyAlias { def_id, span },
+                );
                 // HACK(min_const_generics): Forbid generic `Self` types
                 // here as we can't easily do that during nameres.
                 //
@@ -2061,7 +1836,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
             Res::Def(DefKind::AssocTy, def_id) => {
                 debug_assert!(path.segments.len() >= 2);
-                self.prohibit_generic_args(path.segments[..path.segments.len() - 2].iter(), |_| {});
+                let _ = self.prohibit_generic_args(
+                    path.segments[..path.segments.len() - 2].iter(),
+                    GenericsArgsErrExtend::None,
+                );
                 // HACK: until we support `<Type as ~const Trait>`, assume all of them are.
                 let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
                     ty::BoundConstness::ConstIfConst
@@ -2079,19 +1857,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
             Res::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
-                    let name = prim_ty.name_str();
-                    for segment in path.segments {
-                        if let Some(args) = segment.args {
-                            err.span_suggestion_verbose(
-                                segment.ident.span.shrink_to_hi().to(args.span_ext),
-                                format!("primitive type `{name}` doesn't have generic parameters"),
-                                "",
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                    }
-                });
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
+                    GenericsArgsErrExtend::PrimTy(prim_ty),
+                );
                 match prim_ty {
                     hir::PrimTy::Bool => tcx.types.bool,
                     hir::PrimTy::Char => tcx.types.char,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
index b5b3a9131c5..97ba946b7e0 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
@@ -1,5 +1,4 @@
 use crate::bounds::Bounds;
-use crate::errors::TraitObjectDeclaredWithNoTraits;
 use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::{codes::*, struct_span_code_err};
@@ -7,9 +6,10 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::fold::BottomUpFolder;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{DynKind, ToPredicate};
-use rustc_span::Span;
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
 
@@ -86,47 +86,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
             expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
         if regular_traits.len() > 1 {
-            let first_trait = &regular_traits[0];
-            let additional_trait = &regular_traits[1];
-            let mut err = struct_span_code_err!(
-                tcx.dcx(),
-                additional_trait.bottom().1,
-                E0225,
-                "only auto traits can be used as additional traits in a trait object"
-            );
-            additional_trait.label_with_exp_info(
-                &mut err,
-                "additional non-auto trait",
-                "additional use",
-            );
-            first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
-            err.help(format!(
-                "consider creating a new trait with all of these as supertraits and using that \
-             trait here instead: `trait NewTrait: {} {{}}`",
-                regular_traits
-                    .iter()
-                    // FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
-                    .map(|t| t.trait_ref().print_only_trait_path().to_string())
-                    .collect::<Vec<_>>()
-                    .join(" + "),
-            ));
-            err.note(
-                "auto-traits like `Send` and `Sync` are traits that have special properties; \
-             for more information on them, visit \
-             <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
-            );
-            self.set_tainted_by_errors(err.emit());
-        }
-
-        if regular_traits.is_empty() && auto_traits.is_empty() {
-            let trait_alias_span = trait_bounds
-                .iter()
-                .map(|&(trait_ref, _)| trait_ref.def_id())
-                .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
-                .map(|trait_ref| tcx.def_span(trait_ref));
-            let reported =
-                tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
-            self.set_tainted_by_errors(reported);
+            let _ = self.report_trait_object_addition_traits_error(&regular_traits);
+        } else if regular_traits.is_empty() && auto_traits.is_empty() {
+            let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
             return Ty::new_error(tcx, reported);
         }
 
@@ -267,12 +229,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         if arg == dummy_self.into() {
                             let param = &generics.params[index];
                             missing_type_params.push(param.name);
-                            return Ty::new_misc_error(tcx).into();
+                            Ty::new_misc_error(tcx).into()
                         } else if arg.walk().any(|arg| arg == dummy_self.into()) {
                             references_self = true;
-                            return Ty::new_misc_error(tcx).into();
+                            let guar = tcx.dcx().span_delayed_bug(
+                                span,
+                                "trait object trait bounds reference `Self`",
+                            );
+                            replace_dummy_self_with_error(tcx, arg, guar)
+                        } else {
+                            arg
                         }
-                        arg
                     })
                     .collect();
                 let args = tcx.mk_args(&args);
@@ -327,18 +294,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     let guar = tcx
                         .dcx()
                         .span_delayed_bug(span, "trait object projection bounds reference `Self`");
-                    let args: Vec<_> = b
-                        .projection_ty
-                        .args
-                        .iter()
-                        .map(|arg| {
-                            if arg.walk().any(|arg| arg == dummy_self.into()) {
-                                return Ty::new_error(tcx, guar).into();
-                            }
-                            arg
-                        })
-                        .collect();
-                    b.projection_ty.args = tcx.mk_args(&args);
+                    b.projection_ty = replace_dummy_self_with_error(tcx, b.projection_ty, guar);
                 }
 
                 ty::ExistentialProjection::erase_self_ty(tcx, b)
@@ -396,3 +352,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
     }
 }
+
+fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
+    tcx: TyCtxt<'tcx>,
+    t: T,
+    guar: ErrorGuaranteed,
+) -> T {
+    t.fold_with(&mut BottomUpFolder {
+        tcx,
+        ty_op: |ty| {
+            if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty }
+        },
+        lt_op: |lt| lt,
+        ct_op: |ct| ct,
+    })
+}
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index f7af438ad16..1d51101c940 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -86,12 +86,12 @@ hir_typeck_invalid_callee = expected function, found {$ty}
 hir_typeck_lossy_provenance_int2ptr =
     strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`
     .suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
-    .help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
+    .help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead
 
 hir_typeck_lossy_provenance_ptr2int =
     under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`
     .suggestion = use `.addr()` to obtain the address of a pointer
-    .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+    .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 
 hir_typeck_method_call_on_unknown_raw_pointee =
     cannot call a method on a raw pointer with an unknown pointee type
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 5841392dbcf..59a043d1d69 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -182,7 +182,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>
         ty::Region::new_bound(
             tcx,
             ty::INNERMOST,
-            ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon },
+            ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon },
         ),
         panic_info_ty,
     );
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 011607bacc6..8d4d0833eef 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -11,6 +11,7 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, GenericArg, Node, QPath};
+use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
 use rustc_hir_analysis::hir_ty_lowering::generics::{
     check_generic_arg_count_for_call, lower_generic_args,
 };
@@ -1177,11 +1178,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let indices: FxHashSet<_> =
             generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
-        let generics_has_err = self.lowerer().prohibit_generic_args(
+        let generics_err = self.lowerer().prohibit_generic_args(
             segments.iter().enumerate().filter_map(|(index, seg)| {
                 if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None }
             }),
-            |_| {},
+            GenericsArgsErrExtend::None,
         );
 
         if let Res::Local(hid) = res {
@@ -1191,7 +1192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return (ty, res);
         }
 
-        if generics_has_err {
+        if let Err(_) = generics_err {
             // Don't try to infer type parameters when prohibited generic arguments were given.
             user_self_ty = None;
         }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index ebc5e11a561..f1feffcc82c 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -17,7 +17,8 @@ use itertools::Itertools;
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
-    codes::*, pluralize, Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey,
+    a_or_an, codes::*, display_list_with_comma_and, pluralize, Applicability, Diag,
+    ErrorGuaranteed, MultiSpan, StashKey,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -818,6 +819,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         call_expr,
                         None,
                         Some(mismatch_idx),
+                        &matched_inputs,
+                        &formal_and_expected_inputs,
                         is_method,
                     );
                     suggest_confusable(&mut err);
@@ -904,6 +907,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
             err.span_label(full_call_span, format!("arguments to this {call_name} are incorrect"));
 
+            self.label_generic_mismatches(
+                &mut err,
+                fn_def_id,
+                &matched_inputs,
+                &provided_arg_tys,
+                &formal_and_expected_inputs,
+                is_method,
+            );
+
             if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind
                 && provided_idx.as_usize() == expected_idx.as_usize()
             {
@@ -932,6 +944,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 call_expr,
                 Some(expected_ty),
                 Some(expected_idx.as_usize()),
+                &matched_inputs,
+                &formal_and_expected_inputs,
                 is_method,
             );
             suggest_confusable(&mut err);
@@ -1270,6 +1284,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
+        self.label_generic_mismatches(
+            &mut err,
+            fn_def_id,
+            &matched_inputs,
+            &provided_arg_tys,
+            &formal_and_expected_inputs,
+            is_method,
+        );
+
         // Incorporate the argument changes in the removal suggestion.
         // When a type is *missing*, and the rest are additional, we want to suggest these with a
         // multipart suggestion, but in order to do so we need to figure out *where* the arg that
@@ -1317,7 +1340,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         // Call out where the function is defined
-        self.label_fn_like(&mut err, fn_def_id, callee_ty, call_expr, None, None, is_method);
+        self.label_fn_like(
+            &mut err,
+            fn_def_id,
+            callee_ty,
+            call_expr,
+            None,
+            None,
+            &matched_inputs,
+            &formal_and_expected_inputs,
+            is_method,
+        );
 
         // And add a suggestion block for all of the parameters
         let suggestion_text = match suggestion_text {
@@ -1916,29 +1949,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         pat: &'tcx hir::Pat<'tcx>,
         ty: Ty<'tcx>,
     ) {
-        struct V<'tcx> {
-            tcx: TyCtxt<'tcx>,
-            pat_hir_ids: Vec<hir::HirId>,
-        }
-
-        impl<'tcx> Visitor<'tcx> for V<'tcx> {
-            type NestedFilter = rustc_middle::hir::nested_filter::All;
-
-            fn nested_visit_map(&mut self) -> Self::Map {
-                self.tcx.hir()
+        if let Err(guar) = ty.error_reported() {
+            struct OverwritePatternsWithError {
+                pat_hir_ids: Vec<hir::HirId>,
             }
-
-            fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
-                self.pat_hir_ids.push(p.hir_id);
-                hir::intravisit::walk_pat(self, p);
+            impl<'tcx> Visitor<'tcx> for OverwritePatternsWithError {
+                fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
+                    self.pat_hir_ids.push(p.hir_id);
+                    hir::intravisit::walk_pat(self, p);
+                }
             }
-        }
-        if let Err(guar) = ty.error_reported() {
             // Override the types everywhere with `err()` to avoid knock on errors.
             let err = Ty::new_error(self.tcx, guar);
             self.write_ty(hir_id, err);
             self.write_ty(pat.hir_id, err);
-            let mut visitor = V { tcx: self.tcx, pat_hir_ids: vec![] };
+            let mut visitor = OverwritePatternsWithError { pat_hir_ids: vec![] };
             hir::intravisit::walk_pat(&mut visitor, pat);
             // Mark all the subpatterns as `{type error}` as well. This allows errors for specific
             // subpatterns to be silenced.
@@ -2102,6 +2127,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty: Option<Ty<'tcx>>,
         // A specific argument should be labeled, instead of all of them
         expected_idx: Option<usize>,
+        matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
+        formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
         is_method: bool,
     ) {
         let Some(mut def_id) = callable_def_id else {
@@ -2193,21 +2220,164 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         {
             let mut spans: MultiSpan = def_span.into();
 
-            let params = self
+            let params_with_generics = self.get_hir_params_with_generics(def_id, is_method);
+            let mut generics_with_unmatched_params = Vec::new();
+
+            let check_for_matched_generics = || {
+                if matched_inputs.iter().any(|x| x.is_some())
+                    && params_with_generics.iter().any(|x| x.0.is_some())
+                {
+                    for (idx, (generic, _)) in params_with_generics.iter().enumerate() {
+                        // Param has to have a generic and be matched to be relevant
+                        if matched_inputs[idx.into()].is_none() {
+                            continue;
+                        }
+
+                        let Some(generic) = generic else {
+                            continue;
+                        };
+
+                        for unmatching_idx in idx + 1..params_with_generics.len() {
+                            if matched_inputs[unmatching_idx.into()].is_none()
+                                && let Some(unmatched_idx_param_generic) =
+                                    params_with_generics[unmatching_idx].0
+                                && unmatched_idx_param_generic.name.ident() == generic.name.ident()
+                            {
+                                // We found a parameter that didn't match that needed to
+                                return true;
+                            }
+                        }
+                    }
+                }
+                false
+            };
+
+            let check_for_matched_generics = check_for_matched_generics();
+
+            for (idx, (generic_param, param)) in
+                params_with_generics.iter().enumerate().filter(|(idx, _)| {
+                    check_for_matched_generics
+                        || expected_idx.map_or(true, |expected_idx| expected_idx == *idx)
+                })
+            {
+                let Some(generic_param) = generic_param else {
+                    spans.push_span_label(param.span, "");
+                    continue;
+                };
+
+                let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics
+                    .iter()
+                    .enumerate()
+                    .filter(|(other_idx, (other_generic_param, _))| {
+                        if *other_idx == idx {
+                            return false;
+                        }
+                        let Some(other_generic_param) = other_generic_param else {
+                            return false;
+                        };
+                        if matched_inputs[idx.into()].is_none()
+                            && matched_inputs[(*other_idx).into()].is_none()
+                        {
+                            return false;
+                        }
+                        if matched_inputs[idx.into()].is_some()
+                            && matched_inputs[(*other_idx).into()].is_some()
+                        {
+                            return false;
+                        }
+                        other_generic_param.name.ident() == generic_param.name.ident()
+                    })
+                    .map(|(other_idx, (_, other_param))| (other_idx, *other_param))
+                    .collect();
+
+                if !other_params_matched.is_empty() {
+                    let other_param_matched_names: Vec<String> = other_params_matched
+                        .iter()
+                        .map(|(_, other_param)| {
+                            if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind {
+                                format!("`{ident}`")
+                            } else {
+                                "{unknown}".to_string()
+                            }
+                        })
+                        .collect();
+
+                    let matched_ty = self
+                        .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
+                        .sort_string(self.tcx);
+
+                    if matched_inputs[idx.into()].is_some() {
+                        spans.push_span_label(
+                            param.span,
+                            format!(
+                                "{} {} to match the {} type of this parameter",
+                                display_list_with_comma_and(&other_param_matched_names),
+                                format!(
+                                    "need{}",
+                                    pluralize!(if other_param_matched_names.len() == 1 {
+                                        0
+                                    } else {
+                                        1
+                                    })
+                                ),
+                                matched_ty,
+                            ),
+                        );
+                    } else {
+                        spans.push_span_label(
+                            param.span,
+                            format!(
+                                "this parameter needs to match the {} type of {}",
+                                matched_ty,
+                                display_list_with_comma_and(&other_param_matched_names),
+                            ),
+                        );
+                    }
+                    generics_with_unmatched_params.push(generic_param);
+                } else {
+                    spans.push_span_label(param.span, "");
+                }
+            }
+
+            for generic_param in self
                 .tcx
                 .hir()
                 .get_if_local(def_id)
-                .and_then(|node| node.body_id())
-                .into_iter()
-                .flat_map(|id| self.tcx.hir().body(id).params)
-                .skip(if is_method { 1 } else { 0 });
-
-            for (_, param) in params
+                .and_then(|node| node.generics())
                 .into_iter()
-                .enumerate()
-                .filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx))
+                .flat_map(|x| x.params)
+                .filter(|x| {
+                    generics_with_unmatched_params.iter().any(|y| x.name.ident() == y.name.ident())
+                })
             {
-                spans.push_span_label(param.span, "");
+                let param_idents_matching: Vec<String> = params_with_generics
+                    .iter()
+                    .filter(|(generic, _)| {
+                        if let Some(generic) = generic {
+                            generic.name.ident() == generic_param.name.ident()
+                        } else {
+                            false
+                        }
+                    })
+                    .map(|(_, param)| {
+                        if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind {
+                            format!("`{ident}`")
+                        } else {
+                            "{unknown}".to_string()
+                        }
+                    })
+                    .collect();
+
+                if !param_idents_matching.is_empty() {
+                    spans.push_span_label(
+                        generic_param.span,
+                        format!(
+                            "{} all reference this parameter {}",
+                            display_list_with_comma_and(&param_idents_matching),
+                            generic_param.name.ident().name,
+                        ),
+                    );
+                }
             }
 
             err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
@@ -2268,6 +2438,115 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
         }
     }
+
+    fn label_generic_mismatches(
+        &self,
+        err: &mut Diag<'_>,
+        callable_def_id: Option<DefId>,
+        matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
+        provided_arg_tys: &IndexVec<ProvidedIdx, (Ty<'tcx>, Span)>,
+        formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
+        is_method: bool,
+    ) {
+        let Some(def_id) = callable_def_id else {
+            return;
+        };
+
+        let params_with_generics = self.get_hir_params_with_generics(def_id, is_method);
+
+        for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() {
+            if matched_inputs[idx.into()].is_none() {
+                continue;
+            }
+
+            let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else {
+                continue;
+            };
+
+            let Some(generic_param) = generic_param else {
+                continue;
+            };
+
+            let mut idxs_matched: Vec<usize> = vec![];
+            for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter(
+                |(other_idx, (other_generic_param, _))| {
+                    if *other_idx == idx {
+                        return false;
+                    }
+                    let Some(other_generic_param) = other_generic_param else {
+                        return false;
+                    };
+                    if matched_inputs[(*other_idx).into()].is_some() {
+                        return false;
+                    }
+                    other_generic_param.name.ident() == generic_param.name.ident()
+                },
+            ) {
+                idxs_matched.push(other_idx.into());
+            }
+
+            if idxs_matched.is_empty() {
+                continue;
+            }
+
+            let expected_display_type = self
+                .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
+                .sort_string(self.tcx);
+            let label = if idxs_matched.len() == params_with_generics.len() - 1 {
+                format!(
+                    "expected all arguments to be this {} type because they need to match the type of this parameter",
+                    expected_display_type
+                )
+            } else {
+                format!(
+                    "expected some other arguments to be {} {} type to match the type of this parameter",
+                    a_or_an(&expected_display_type),
+                    expected_display_type,
+                )
+            };
+
+            err.span_label(*matched_arg_span, label);
+        }
+    }
+
+    fn get_hir_params_with_generics(
+        &self,
+        def_id: DefId,
+        is_method: bool,
+    ) -> Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)> {
+        let fn_node = self.tcx.hir().get_if_local(def_id);
+
+        let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_node
+            .and_then(|node| node.fn_decl())
+            .into_iter()
+            .flat_map(|decl| decl.inputs)
+            .skip(if is_method { 1 } else { 0 })
+            .map(|param| {
+                if let hir::TyKind::Path(QPath::Resolved(
+                    _,
+                    hir::Path { res: Res::Def(_, res_def_id), .. },
+                )) = param.kind
+                {
+                    fn_node
+                        .and_then(|node| node.generics())
+                        .into_iter()
+                        .flat_map(|generics| generics.params)
+                        .find(|gen| &gen.def_id.to_def_id() == res_def_id)
+                } else {
+                    None
+                }
+            })
+            .collect();
+
+        let params: Vec<&hir::Param<'_>> = fn_node
+            .and_then(|node| node.body_id())
+            .into_iter()
+            .flat_map(|id| self.tcx.hir().body(id).params)
+            .skip(if is_method { 1 } else { 0 })
+            .collect();
+
+        generic_params.into_iter().zip(params).collect()
+    }
 }
 
 struct FindClosureArg<'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 74f27cfebbd..05e7c5b2b41 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -416,13 +416,13 @@ fn parse_never_type_options_attr(
             continue;
         }
 
-        if item.has_name(sym::diverging_block_default) && fallback.is_none() {
-            let mode = item.value_str().unwrap();
-            match mode {
+        if item.has_name(sym::diverging_block_default) && block.is_none() {
+            let default = item.value_str().unwrap();
+            match default {
                 sym::unit => block = Some(DivergingBlockBehavior::Unit),
                 sym::never => block = Some(DivergingBlockBehavior::Never),
                 _ => {
-                    tcx.dcx().span_err(item.span(), format!("unknown diverging block default: `{mode}` (supported: `unit` and `never`)"));
+                    tcx.dcx().span_err(item.span(), format!("unknown diverging block default: `{default}` (supported: `unit` and `never`)"));
                 }
             };
             continue;
@@ -431,7 +431,7 @@ fn parse_never_type_options_attr(
         tcx.dcx().span_err(
             item.span(),
             format!(
-                "unknown never type option: `{}` (supported: `fallback`)",
+                "unknown or duplicate never type option: `{}` (supported: `fallback`, `diverging_block_default`)",
                 item.name_or_empty()
             ),
         );
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 9e3867e630d..62711e40049 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -17,7 +17,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
         let data_idx;
 
         let one = VariantIdx::new(1);
-        let zero = VariantIdx::new(0);
+        let zero = VariantIdx::ZERO;
 
         if def.variant(zero).fields.is_empty() {
             data_idx = one;
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 12f522d1adc..a199f57aad9 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -774,7 +774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         let projection_ty = pred.skip_binder().projection_ty;
 
                         let args_with_infer_self = tcx.mk_args_from_iter(
-                            iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into())
+                            iter::once(Ty::new_var(tcx, ty::TyVid::ZERO).into())
                                 .chain(projection_ty.args.iter().skip(1)),
                         );
 
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 54344adaabd..72e5b1ed95b 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -343,10 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let closure_env_region: ty::Region<'_> = ty::Region::new_bound(
                 self.tcx,
                 ty::INNERMOST,
-                ty::BoundRegion {
-                    var: ty::BoundVar::from_usize(0),
-                    kind: ty::BoundRegionKind::BrEnv,
-                },
+                ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::BrEnv },
             );
             let tupled_upvars_ty_for_borrow = Ty::new_tup_from_iter(
                 self.tcx,
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 12f8e42c78f..c7e563035fc 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -400,7 +400,7 @@ enum Chunk {
 }
 
 // This type is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 crate::static_assert_size!(Chunk, 16);
 
 impl<T> ChunkedBitSet<T> {
diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs
index e5c2ba42483..fe9a048734f 100644
--- a/compiler/rustc_index_macros/src/newtype.rs
+++ b/compiler/rustc_index_macros/src/newtype.rs
@@ -174,6 +174,9 @@ impl Parse for Newtype {
                 /// Maximum value the index can take.
                 #vis const MAX: Self = Self::from_u32(#max);
 
+                /// Zero value of the index.
+                #vis const ZERO: Self = Self::from_u32(0);
+
                 /// Creates a new index from a given `usize`.
                 ///
                 /// # Panics
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 339c8ac10b3..3e89327d20f 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -483,7 +483,7 @@ pub enum SubregionOrigin<'tcx> {
 }
 
 // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(SubregionOrigin<'_>, 32);
 
 impl<'tcx> SubregionOrigin<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
index 14de461cd17..f8f1c1b4c45 100644
--- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
@@ -13,7 +13,7 @@ use ut::UnifyKey;
 use std::ops::Range;
 
 fn vars_since_snapshot<'tcx, T>(
-    table: &mut UnificationTable<'_, 'tcx, T>,
+    table: &UnificationTable<'_, 'tcx, T>,
     snapshot_var_len: usize,
 ) -> Range<T>
 where
@@ -124,11 +124,11 @@ impl<'tcx> InferCtxt<'tcx> {
                     let type_vars =
                         inner.type_variables().vars_since_snapshot(variable_lengths.type_var_len);
                     let int_vars = vars_since_snapshot(
-                        &mut inner.int_unification_table(),
+                        &inner.int_unification_table(),
                         variable_lengths.int_var_len,
                     );
                     let float_vars = vars_since_snapshot(
-                        &mut inner.float_unification_table(),
+                        &inner.float_unification_table(),
                         variable_lengths.float_var_len,
                     );
                     let region_vars = inner
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index ee9ce842d00..0444cbe2ee4 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -32,7 +32,7 @@
 
 #[macro_use]
 extern crate rustc_macros;
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 #[macro_use]
 extern crate rustc_data_structures;
 #[macro_use]
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 616f5cc0456..94ad0f5b1c8 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -112,7 +112,7 @@ impl<'tcx> PolyTraitObligation<'tcx> {
 }
 
 // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(PredicateObligation<'_>, 48);
 
 pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index d763a12f816..1f92cc4d763 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -748,9 +748,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
 
     sess.time("MIR_effect_checking", || {
         for def_id in tcx.hir().body_owners() {
-            if !tcx.sess.opts.unstable_opts.thir_unsafeck {
-                rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
-            }
             tcx.ensure().has_ffi_unwind_calls(def_id);
 
             // If we need to codegen, ensure that we emit all errors from
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 3b78e6a43ab..b9025917d13 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -840,7 +840,6 @@ fn test_unstable_options_tracking_hash() {
     tracked!(stack_protector, StackProtector::All);
     tracked!(teach, true);
     tracked!(thinlto, Some(true));
-    tracked!(thir_unsafeck, false);
     tracked!(tiny_const_eval_limit, true);
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(translate_remapped_path_to_local_path, false);
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 1dac2d89c6b..a034bebc85e 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1632,11 +1632,13 @@ pub struct AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a> {
     pub ne: &'a str,
     pub deref_left: &'a str,
     pub deref_right: &'a str,
+    pub l_modifiers: &'a str,
+    pub r_modifiers: &'a str,
     #[suggestion_part(code = "{ne}std::ptr::eq({deref_left}")]
     pub left: Span,
-    #[suggestion_part(code = ", {deref_right}")]
+    #[suggestion_part(code = "{l_modifiers}, {deref_right}")]
     pub middle: Span,
-    #[suggestion_part(code = ")")]
+    #[suggestion_part(code = "{r_modifiers})")]
     pub right: Span,
 }
 
@@ -1652,11 +1654,13 @@ pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
         ne: &'a str,
         deref_left: &'a str,
         deref_right: &'a str,
+        l_modifiers: &'a str,
+        r_modifiers: &'a str,
         #[suggestion_part(code = "{ne}std::ptr::addr_eq({deref_left}")]
         left: Span,
-        #[suggestion_part(code = ", {deref_right}")]
+        #[suggestion_part(code = "{l_modifiers}, {deref_right}")]
         middle: Span,
-        #[suggestion_part(code = ")")]
+        #[suggestion_part(code = "{r_modifiers})")]
         right: Span,
     },
     #[multipart_suggestion(
@@ -1668,14 +1672,18 @@ pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
     Cast {
         deref_left: &'a str,
         deref_right: &'a str,
-        #[suggestion_part(code = "{deref_left}")]
+        paren_left: &'a str,
+        paren_right: &'a str,
+        l_modifiers: &'a str,
+        r_modifiers: &'a str,
+        #[suggestion_part(code = "({deref_left}")]
         left_before: Option<Span>,
-        #[suggestion_part(code = " as *const ()")]
-        left: Span,
-        #[suggestion_part(code = "{deref_right}")]
+        #[suggestion_part(code = "{l_modifiers}{paren_left}.cast::<()>()")]
+        left_after: Span,
+        #[suggestion_part(code = "({deref_right}")]
         right_before: Option<Span>,
-        #[suggestion_part(code = " as *const ()")]
-        right: Span,
+        #[suggestion_part(code = "{r_modifiers}{paren_right}.cast::<()>()")]
+        right_after: Span,
     },
 }
 
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 5331d2fb752..534eb60eeb0 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -657,14 +657,24 @@ fn lint_nan<'tcx>(
     cx.emit_span_lint(INVALID_NAN_COMPARISONS, e.span, lint);
 }
 
+#[derive(Debug, PartialEq)]
+enum ComparisonOp {
+    BinOp(hir::BinOpKind),
+    Other,
+}
+
 fn lint_wide_pointer<'tcx>(
     cx: &LateContext<'tcx>,
     e: &'tcx hir::Expr<'tcx>,
-    binop: hir::BinOpKind,
+    cmpop: ComparisonOp,
     l: &'tcx hir::Expr<'tcx>,
     r: &'tcx hir::Expr<'tcx>,
 ) {
-    let ptr_unsized = |mut ty: Ty<'tcx>| -> Option<(usize, bool)> {
+    let ptr_unsized = |mut ty: Ty<'tcx>| -> Option<(
+        /* number of refs */ usize,
+        /* modifiers */ String,
+        /* is dyn */ bool,
+    )> {
         let mut refs = 0;
         // here we remove any "implicit" references and count the number
         // of them to correctly suggest the right number of deref
@@ -672,14 +682,23 @@ fn lint_wide_pointer<'tcx>(
             ty = *inner_ty;
             refs += 1;
         }
-        match ty.kind() {
-            ty::RawPtr(ty, _) => (!ty.is_sized(cx.tcx, cx.param_env))
-                .then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))),
-            _ => None,
-        }
+
+        // get the inner type of a pointer (or akin)
+        let mut modifiers = String::new();
+        ty = match ty.kind() {
+            ty::RawPtr(ty, _) => *ty,
+            ty::Adt(def, args) if cx.tcx.is_diagnostic_item(sym::NonNull, def.did()) => {
+                modifiers.push_str(".as_ptr()");
+                args.type_at(0)
+            }
+            _ => return None,
+        };
+
+        (!ty.is_sized(cx.tcx, cx.param_env))
+            .then(|| (refs, modifiers, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn))))
     };
 
-    // PartialEq::{eq,ne} takes references, remove any explicit references
+    // the left and right operands can have references, remove any explicit references
     let l = l.peel_borrows();
     let r = r.peel_borrows();
 
@@ -690,10 +709,10 @@ fn lint_wide_pointer<'tcx>(
         return;
     };
 
-    let Some((l_ty_refs, l_inner_ty_is_dyn)) = ptr_unsized(l_ty) else {
+    let Some((l_ty_refs, l_modifiers, l_inner_ty_is_dyn)) = ptr_unsized(l_ty) else {
         return;
     };
-    let Some((r_ty_refs, r_inner_ty_is_dyn)) = ptr_unsized(r_ty) else {
+    let Some((r_ty_refs, r_modifiers, r_inner_ty_is_dyn)) = ptr_unsized(r_ty) else {
         return;
     };
 
@@ -707,8 +726,8 @@ fn lint_wide_pointer<'tcx>(
         );
     };
 
-    let ne = if binop == hir::BinOpKind::Ne { "!" } else { "" };
-    let is_eq_ne = matches!(binop, hir::BinOpKind::Eq | hir::BinOpKind::Ne);
+    let ne = if cmpop == ComparisonOp::BinOp(hir::BinOpKind::Ne) { "!" } else { "" };
+    let is_eq_ne = matches!(cmpop, ComparisonOp::BinOp(hir::BinOpKind::Eq | hir::BinOpKind::Ne));
     let is_dyn_comparison = l_inner_ty_is_dyn && r_inner_ty_is_dyn;
 
     let left = e.span.shrink_to_lo().until(l_span.shrink_to_lo());
@@ -718,6 +737,9 @@ fn lint_wide_pointer<'tcx>(
     let deref_left = &*"*".repeat(l_ty_refs);
     let deref_right = &*"*".repeat(r_ty_refs);
 
+    let l_modifiers = &*l_modifiers;
+    let r_modifiers = &*r_modifiers;
+
     cx.emit_span_lint(
         AMBIGUOUS_WIDE_POINTER_COMPARISONS,
         e.span,
@@ -727,6 +749,8 @@ fn lint_wide_pointer<'tcx>(
                     ne,
                     deref_left,
                     deref_right,
+                    l_modifiers,
+                    r_modifiers,
                     left,
                     middle,
                     right,
@@ -737,6 +761,8 @@ fn lint_wide_pointer<'tcx>(
                     ne,
                     deref_left,
                     deref_right,
+                    l_modifiers,
+                    r_modifiers,
                     left,
                     middle,
                     right,
@@ -745,12 +771,14 @@ fn lint_wide_pointer<'tcx>(
                 AmbiguousWidePointerComparisonsAddrSuggestion::Cast {
                     deref_left,
                     deref_right,
-                    // those two Options are required for correctness as having
-                    // an empty span and an empty suggestion is not permitted
-                    left_before: (l_ty_refs != 0).then_some(left),
-                    right_before: (r_ty_refs != 0).then(|| r_span.shrink_to_lo()),
-                    left: l_span.shrink_to_hi(),
-                    right,
+                    l_modifiers,
+                    r_modifiers,
+                    paren_left: if l_ty_refs != 0 { ")" } else { "" },
+                    paren_right: if r_ty_refs != 0 { ")" } else { "" },
+                    left_before: (l_ty_refs != 0).then_some(l_span.shrink_to_lo()),
+                    left_after: l_span.shrink_to_hi(),
+                    right_before: (r_ty_refs != 0).then_some(r_span.shrink_to_lo()),
+                    right_after: r_span.shrink_to_hi(),
                 }
             },
         },
@@ -773,7 +801,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
                         cx.emit_span_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons);
                     } else {
                         lint_nan(cx, e, binop, l, r);
-                        lint_wide_pointer(cx, e, binop.node, l, r);
+                        lint_wide_pointer(cx, e, ComparisonOp::BinOp(binop.node), l, r);
                     }
                 }
             }
@@ -782,16 +810,16 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
                 if let ExprKind::Path(ref qpath) = path.kind
                     && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
                     && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
-                    && let Some(binop) = partialeq_binop(diag_item) =>
+                    && let Some(cmpop) = diag_item_cmpop(diag_item) =>
             {
-                lint_wide_pointer(cx, e, binop, l, r);
+                lint_wide_pointer(cx, e, cmpop, l, r);
             }
             hir::ExprKind::MethodCall(_, l, [r], _)
                 if let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
                     && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
-                    && let Some(binop) = partialeq_binop(diag_item) =>
+                    && let Some(cmpop) = diag_item_cmpop(diag_item) =>
             {
-                lint_wide_pointer(cx, e, binop, l, r);
+                lint_wide_pointer(cx, e, cmpop, l, r);
             }
             _ => {}
         };
@@ -876,14 +904,20 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
             )
         }
 
-        fn partialeq_binop(diag_item: Symbol) -> Option<hir::BinOpKind> {
-            if diag_item == sym::cmp_partialeq_eq {
-                Some(hir::BinOpKind::Eq)
-            } else if diag_item == sym::cmp_partialeq_ne {
-                Some(hir::BinOpKind::Ne)
-            } else {
-                None
-            }
+        fn diag_item_cmpop(diag_item: Symbol) -> Option<ComparisonOp> {
+            Some(match diag_item {
+                sym::cmp_ord_max => ComparisonOp::Other,
+                sym::cmp_ord_min => ComparisonOp::Other,
+                sym::ord_cmp_method => ComparisonOp::Other,
+                sym::cmp_partialeq_eq => ComparisonOp::BinOp(hir::BinOpKind::Eq),
+                sym::cmp_partialeq_ne => ComparisonOp::BinOp(hir::BinOpKind::Ne),
+                sym::cmp_partialord_cmp => ComparisonOp::Other,
+                sym::cmp_partialord_ge => ComparisonOp::BinOp(hir::BinOpKind::Ge),
+                sym::cmp_partialord_gt => ComparisonOp::BinOp(hir::BinOpKind::Gt),
+                sym::cmp_partialord_le => ComparisonOp::BinOp(hir::BinOpKind::Le),
+                sym::cmp_partialord_lt => ComparisonOp::BinOp(hir::BinOpKind::Lt),
+                _ => return None,
+            })
         }
     }
 }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 9f09f46ea5a..30522628f46 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2749,7 +2749,7 @@ declare_lint! {
     /// memory the pointer is allowed to read/write. Casting an integer, which
     /// doesn't have provenance, to a pointer requires the compiler to assign
     /// (guess) provenance. The compiler assigns "all exposed valid" (see the
-    /// docs of [`ptr::from_exposed_addr`] for more information about this
+    /// docs of [`ptr::with_exposed_provenance`] for more information about this
     /// "exposing"). This penalizes the optimiser and is not well suited for
     /// dynamic analysis/dynamic program verification (e.g. Miri or CHERI
     /// platforms).
@@ -2757,11 +2757,11 @@ declare_lint! {
     /// It is much better to use [`ptr::with_addr`] instead to specify the
     /// provenance you want. If using this function is not possible because the
     /// code relies on exposed provenance then there is as an escape hatch
-    /// [`ptr::from_exposed_addr`].
+    /// [`ptr::with_exposed_provenance`].
     ///
     /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
     /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.with_addr
-    /// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr.html
+    /// [`ptr::with_exposed_provenance`]: https://doc.rust-lang.org/core/ptr/fn.with_exposed_provenance.html
     pub FUZZY_PROVENANCE_CASTS,
     Allow,
     "a fuzzy integer to pointer cast is used",
@@ -2797,17 +2797,17 @@ declare_lint! {
     /// Since this cast is lossy, it is considered good style to use the
     /// [`ptr::addr`] method instead, which has a similar effect, but doesn't
     /// "expose" the pointer provenance. This improves optimisation potential.
-    /// See the docs of [`ptr::addr`] and [`ptr::expose_addr`] for more information
+    /// See the docs of [`ptr::addr`] and [`ptr::expose_provenance`] for more information
     /// about exposing pointer provenance.
     ///
     /// If your code can't comply with strict provenance and needs to expose
-    /// the provenance, then there is [`ptr::expose_addr`] as an escape hatch,
+    /// the provenance, then there is [`ptr::expose_provenance`] as an escape hatch,
     /// which preserves the behaviour of `as usize` casts while being explicit
     /// about the semantics.
     ///
     /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
     /// [`ptr::addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.addr
-    /// [`ptr::expose_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.expose_addr
+    /// [`ptr::expose_provenance`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.expose_provenance
     pub LOSSY_PROVENANCE_CASTS,
     Allow,
     "a lossy pointer to integer cast is used",
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 4b0c1229da1..e2c0ec90c7c 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -391,6 +391,12 @@ fn main() {
         }
     }
 
+    // libc++abi and libunwind have to be specified explicitly on AIX.
+    if target.contains("aix") {
+        println!("cargo:rustc-link-lib=c++abi");
+        println!("cargo:rustc-link-lib=unwind");
+    }
+
     // Libstdc++ depends on pthread which Rust doesn't link on MinGW
     // since nothing else requires it.
     if target.ends_with("windows-gnu") {
diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml
index 6009a43e985..3ff86f700a5 100644
--- a/compiler/rustc_log/Cargo.toml
+++ b/compiler/rustc_log/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2021"
 tracing = "0.1.28"
 tracing-core = "=0.1.30" # FIXME(Nilstrieb) tracing has a deadlock: https://github.com/tokio-rs/tracing/issues/2635
 tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
-tracing-tree = "0.2.0"
+tracing-tree = "0.3.0"
 # tidy-alphabetical-end
 
 [dev-dependencies]
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 61060038b50..7b10ea53524 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -549,17 +549,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
             match source_file.name {
                 FileName::Real(ref original_file_name) => {
-                    let adapted_file_name = if self.tcx.sess.should_prefer_remapped_for_codegen() {
-                        source_map.path_mapping().to_embeddable_absolute_path(
-                            original_file_name.clone(),
-                            working_directory,
-                        )
-                    } else {
-                        source_map.path_mapping().to_local_embeddable_absolute_path(
-                            original_file_name.clone(),
-                            working_directory,
-                        )
-                    };
+                    // FIXME: This should probably to conditionally remapped under
+                    // a RemapPathScopeComponents but which one?
+                    let adapted_file_name = source_map
+                        .path_mapping()
+                        .to_embeddable_absolute_path(original_file_name.clone(), working_directory);
 
                     adapted_source_file.name = FileName::Real(adapted_file_name);
                 }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index c90427256b8..bd11b3eb04c 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -35,7 +35,6 @@ macro_rules! arena_types {
             )>,
             [] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>,
             [] resolutions: rustc_middle::ty::ResolverGlobalCtxt,
-            [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
             [decode] code_region: rustc_middle::mir::coverage::CodeRegion,
             [] const_allocs: rustc_middle::mir::interpret::Allocation,
             [] region_scope_tree: rustc_middle::middle::region::ScopeTree,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 53cb05198cd..72f849b534a 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -13,7 +13,6 @@ use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::*;
-use rustc_index::Idx;
 use rustc_middle::hir::nested_filter;
 use rustc_span::def_id::StableCrateId;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -69,7 +68,7 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> {
 
     fn next(&mut self) -> Option<Self::Item> {
         if self.current_id.local_id.index() != 0 {
-            self.current_id.local_id = ItemLocalId::new(0);
+            self.current_id.local_id = ItemLocalId::ZERO;
             let node = self.map.tcx.hir_owner_node(self.current_id.owner);
             return Some((self.current_id.owner, node));
         }
@@ -133,7 +132,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
     pub fn parent_hir_id(self, hir_id: HirId) -> HirId {
         let HirId { owner, local_id } = hir_id;
-        if local_id == ItemLocalId::from_u32(0) {
+        if local_id == ItemLocalId::ZERO {
             self.hir_owner_parent(owner)
         } else {
             let parent_local_id = self.hir_owner_nodes(owner).nodes[local_id].parent;
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 28f7574f66f..42a06c968c7 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -174,8 +174,12 @@ pub fn provide(providers: &mut Providers) {
             let parent_owner_id = tcx.local_def_id_to_hir_id(parent_def_id).owner;
             HirId {
                 owner: parent_owner_id,
-                local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id].unwrap().parenting
-                    [&owner_id.def_id],
+                local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id]
+                    .unwrap()
+                    .parenting
+                    .get(&owner_id.def_id)
+                    .copied()
+                    .unwrap_or(ItemLocalId::from_u32(0)),
             }
         })
     };
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 7b65c11bc3c..acea89e4aab 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -82,7 +82,7 @@ impl CanonicalVarValues<'_> {
     }
 
     pub fn is_identity_modulo_regions(&self) -> bool {
-        let mut var = ty::BoundVar::from_u32(0);
+        let mut var = ty::BoundVar::ZERO;
         for arg in self.var_values {
             match arg.unpack() {
                 ty::GenericArgKind::Lifetime(r) => {
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 7d6d39a2a8a..ec9697bbd35 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -1,6 +1,7 @@
 use crate::mir::mono::Linkage;
 use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_span::symbol::Symbol;
+use rustc_target::abi::Align;
 use rustc_target::spec::SanitizerSet;
 
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
@@ -42,7 +43,7 @@ pub struct CodegenFnAttrs {
     pub instruction_set: Option<InstructionSetAttr>,
     /// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be
     /// aligned to.
-    pub alignment: Option<u32>,
+    pub alignment: Option<Align>,
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 500536a9e9e..46520d69e18 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -2,7 +2,7 @@
 //! outside their scopes. This pass will also generate a set of exported items
 //! which are available for use externally when compiled as a library.
 use crate::ty::{TyCtxt, Visibility};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def::DefKind;
 use rustc_macros::HashStable;
@@ -90,7 +90,7 @@ impl EffectiveVisibility {
 /// Holds a map of effective visibilities for reachable HIR nodes.
 #[derive(Clone, Debug)]
 pub struct EffectiveVisibilities<Id = LocalDefId> {
-    map: FxHashMap<Id, EffectiveVisibility>,
+    map: FxIndexMap<Id, EffectiveVisibility>,
 }
 
 impl EffectiveVisibilities {
@@ -130,9 +130,8 @@ impl EffectiveVisibilities {
         eff_vis: &EffectiveVisibility,
         tcx: TyCtxt<'_>,
     ) {
-        use std::collections::hash_map::Entry;
         match self.map.entry(def_id) {
-            Entry::Occupied(mut occupied) => {
+            IndexEntry::Occupied(mut occupied) => {
                 let old_eff_vis = occupied.get_mut();
                 for l in Level::all_levels() {
                     let vis_at_level = eff_vis.at_level(l);
@@ -145,7 +144,7 @@ impl EffectiveVisibilities {
                 }
                 old_eff_vis
             }
-            Entry::Vacant(vacant) => vacant.insert(*eff_vis),
+            IndexEntry::Vacant(vacant) => vacant.insert(*eff_vis),
         };
     }
 
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 02185cbeacf..155af062012 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -1,7 +1,7 @@
 use std::fmt::{self, Debug, Display, Formatter};
 
 use rustc_hir::def_id::DefId;
-use rustc_session::RemapFileNameExt;
+use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{HasDataLayout, Size};
 
@@ -70,7 +70,7 @@ pub enum ConstValue<'tcx> {
     },
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(ConstValue<'_>, 24);
 
 impl<'tcx> ConstValue<'tcx> {
@@ -516,7 +516,11 @@ impl<'tcx> TyCtxt<'tcx> {
         let caller = self.sess.source_map().lookup_char_pos(topmost.lo());
         self.const_caller_location(
             rustc_span::symbol::Symbol::intern(
-                &caller.file.name.for_codegen(self.sess).to_string_lossy(),
+                &caller
+                    .file
+                    .name
+                    .for_scope(self.sess, RemapPathScopeComponents::MACRO)
+                    .to_string_lossy(),
             ),
             caller.line as u32,
             caller.col_display as u32 + 1,
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 588aa1f40d7..0c91dc6d3c6 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -34,7 +34,7 @@ rustc_index::newtype_index! {
 }
 
 impl CounterId {
-    pub const START: Self = Self::from_u32(0);
+    pub const START: Self = Self::ZERO;
 }
 
 rustc_index::newtype_index! {
@@ -56,7 +56,7 @@ rustc_index::newtype_index! {
 }
 
 impl ExpressionId {
-    pub const START: Self = Self::from_u32(0);
+    pub const START: Self = Self::ZERO;
 }
 
 /// Enum that can hold a constant zero value, the ID of an physical coverage
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index c86970635a5..e9be26d058b 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -88,7 +88,7 @@ pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
 /// This is needed in `thir::pattern::lower_inline_const`.
 pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(InterpErrorInfo<'_>, 8);
 
 /// Packages the kind of error we got from the const code interpreter
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 24d4a79c7d7..9f9433e483b 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -37,7 +37,7 @@ pub enum Scalar<Prov = CtfeProvenance> {
     Ptr(Pointer<Prov>, u8),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(Scalar, 24);
 
 // We want the `Debug` output to be readable as it is used by `derive(Debug)` for
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index e5a650c5ac4..ad166620bcc 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -845,17 +845,6 @@ impl<'tcx> Body<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
-pub enum Safety {
-    Safe,
-    /// Unsafe because of compiler-generated unsafe code, like `await` desugaring
-    BuiltinUnsafe,
-    /// Unsafe because of an unsafe fn
-    FnUnsafe,
-    /// Unsafe because of an `unsafe` block
-    ExplicitUnsafe(hir::HirId),
-}
-
 impl<'tcx> Index<BasicBlock> for Body<'tcx> {
     type Output = BasicBlockData<'tcx>;
 
@@ -1611,8 +1600,6 @@ pub struct SourceScopeData<'tcx> {
 pub struct SourceScopeLocalData {
     /// An `HirId` with lint levels equivalent to this scope's lint levels.
     pub lint_root: hir::HirId,
-    /// The unsafe block that contains this node.
-    pub safety: Safety,
 }
 
 /// A collection of projections into user types.
@@ -1881,14 +1868,14 @@ impl DefLocation {
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
     // tidy-alphabetical-start
     static_assert_size!(BasicBlockData<'_>, 144);
     static_assert_size!(LocalDecl<'_>, 40);
-    static_assert_size!(SourceScopeData<'_>, 72);
+    static_assert_size!(SourceScopeData<'_>, 64);
     static_assert_size!(Statement<'_>, 32);
     static_assert_size!(StatementKind<'_>, 16);
     static_assert_size!(Terminator<'_>, 112);
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 731e050ca9b..0f622127430 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -3,9 +3,7 @@
 use crate::mir;
 use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_data_structures::unord::UnordSet;
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_index::bit_set::BitMatrix;
 use rustc_index::{Idx, IndexVec};
@@ -18,67 +16,6 @@ use std::fmt::{self, Debug};
 
 use super::{ConstValue, SourceInfo};
 
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
-pub enum UnsafetyViolationKind {
-    /// Unsafe operation outside `unsafe`.
-    General,
-    /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
-    /// Has to be handled as a lint for backwards compatibility.
-    UnsafeFn,
-}
-
-#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
-pub enum UnsafetyViolationDetails {
-    CallToUnsafeFunction,
-    UseOfInlineAssembly,
-    InitializingTypeWith,
-    CastOfPointerToInt,
-    UseOfMutableStatic,
-    UseOfExternStatic,
-    DerefOfRawPointer,
-    AccessToUnionField,
-    MutationOfLayoutConstrainedField,
-    BorrowOfLayoutConstrainedField,
-    CallToFunctionWith {
-        /// Target features enabled in callee's `#[target_feature]` but missing in
-        /// caller's `#[target_feature]`.
-        missing: Vec<Symbol>,
-        /// Target features in `missing` that are enabled at compile time
-        /// (e.g., with `-C target-feature`).
-        build_enabled: Vec<Symbol>,
-    },
-}
-
-#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
-pub struct UnsafetyViolation {
-    pub source_info: SourceInfo,
-    pub lint_root: hir::HirId,
-    pub kind: UnsafetyViolationKind,
-    pub details: UnsafetyViolationDetails,
-}
-
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
-pub enum UnusedUnsafe {
-    /// `unsafe` block contains no unsafe operations
-    /// > ``unnecessary `unsafe` block``
-    Unused,
-    /// `unsafe` block nested under another (used) `unsafe` block
-    /// > ``… because it's nested under this `unsafe` block``
-    InUnsafeBlock(hir::HirId),
-}
-
-#[derive(TyEncodable, TyDecodable, HashStable, Debug)]
-pub struct UnsafetyCheckResult {
-    /// Violations that are propagated *upwards* from this function.
-    pub violations: Vec<UnsafetyViolation>,
-
-    /// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
-    pub used_unsafe_blocks: UnordSet<hir::HirId>,
-
-    /// This is `Some` iff the item is not a closure.
-    pub unused_unsafes: Option<Vec<(hir::HirId, UnusedUnsafe)>>,
-}
-
 rustc_index::newtype_index! {
     #[derive(HashStable)]
     #[encodable]
@@ -276,7 +213,7 @@ pub struct ClosureOutlivesRequirement<'tcx> {
 }
 
 // Make sure this enum doesn't unintentionally grow
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
 
 /// Outlives-constraints can be categorized to determine whether and why they
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index f929a5cec25..069c8019cb2 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -409,7 +409,7 @@ impl<'tcx> Rvalue<'tcx> {
             // Pointer to int casts may be side-effects due to exposing the provenance.
             // While the model is undecided, we should be conservative. See
             // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
-            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
+            Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => false,
 
             Rvalue::Use(_)
             | Rvalue::CopyForDeref(_)
@@ -426,7 +426,7 @@ impl<'tcx> Rvalue<'tcx> {
                 | CastKind::FnPtrToPtr
                 | CastKind::PtrToPtr
                 | CastKind::PointerCoercion(_)
-                | CastKind::PointerFromExposedAddress
+                | CastKind::PointerWithExposedProvenance
                 | CastKind::DynStar
                 | CastKind::Transmute,
                 _,
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 2fe63fe4cb8..c78c225b0cd 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1309,11 +1309,11 @@ pub enum Rvalue<'tcx> {
 pub enum CastKind {
     /// An exposing pointer to address cast. A cast between a pointer and an integer type, or
     /// between a function pointer and an integer type.
-    /// See the docs on `expose_addr` for more details.
-    PointerExposeAddress,
+    /// See the docs on `expose_provenance` for more details.
+    PointerExposeProvenance,
     /// An address-to-pointer cast that picks up an exposed provenance.
-    /// See the docs on `from_exposed_addr` for more details.
-    PointerFromExposedAddress,
+    /// See the docs on `with_exposed_provenance` for more details.
+    PointerWithExposedProvenance,
     /// Pointer related casts that are done by coercions. Note that reference-to-raw-ptr casts are
     /// translated into `&raw mut/const *r`, i.e., they are not actually casts.
     PointerCoercion(PointerCoercion),
@@ -1438,12 +1438,22 @@ pub enum BinOp {
     Ge,
     /// The `>` operator (greater than)
     Gt,
+    /// The `<=>` operator (three-way comparison, like `Ord::cmp`)
+    ///
+    /// This is supported only on the integer types and `char`, always returning
+    /// [`rustc_hir::LangItem::OrderingEnum`] (aka [`std::cmp::Ordering`]).
+    ///
+    /// [`Rvalue::BinaryOp`]`(BinOp::Cmp, A, B)` returns
+    /// - `Ordering::Less` (`-1_i8`, as a Scalar) if `A < B`
+    /// - `Ordering::Equal` (`0_i8`, as a Scalar) if `A == B`
+    /// - `Ordering::Greater` (`+1_i8`, as a Scalar) if `A > B`
+    Cmp,
     /// The `ptr.offset` operator
     Offset,
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     // tidy-alphabetical-start
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 56a0a623397..b86aa601ce8 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -14,7 +14,7 @@ pub struct PlaceTy<'tcx> {
 }
 
 // At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(PlaceTy<'_>, 16);
 
 impl<'tcx> PlaceTy<'tcx> {
@@ -276,6 +276,11 @@ impl<'tcx> BinOp {
             &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)
+            }
         }
     }
 }
@@ -312,7 +317,8 @@ impl BinOp {
             BinOp::Gt => hir::BinOpKind::Gt,
             BinOp::Le => hir::BinOpKind::Le,
             BinOp::Ge => hir::BinOpKind::Ge,
-            BinOp::AddUnchecked
+            BinOp::Cmp
+            | BinOp::AddUnchecked
             | BinOp::SubUnchecked
             | BinOp::MulUnchecked
             | BinOp::ShlUnchecked
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 3835bd371d9..4f7b2f7cbe4 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -341,7 +341,7 @@ macro_rules! make_mir_visitor {
 
                         ty::InstanceDef::Intrinsic(_def_id) |
                         ty::InstanceDef::VTableShim(_def_id) |
-                        ty::InstanceDef::ReifyShim(_def_id) |
+                        ty::InstanceDef::ReifyShim(_def_id, _) |
                         ty::InstanceDef::Virtual(_def_id, _) |
                         ty::InstanceDef::ThreadLocalShim(_def_id) |
                         ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 5e4454db3e2..62a60a650ec 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -877,12 +877,6 @@ rustc_queries! {
         desc { |tcx| "collecting all inherent impls for `{:?}`", key }
     }
 
-    /// The result of unsafety-checking this `LocalDefId` with the old checker.
-    query mir_unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
-        desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
-        cache_on_disk_if { true }
-    }
-
     /// Unsafety-check this `LocalDefId`.
     query check_unsafety(key: LocalDefId) {
         desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index e3588a7afdc..8cb4ee7bd41 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -339,7 +339,7 @@ macro_rules! define_callbacks {
                 pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erase<$V>>;
 
                 // Ensure that keys grow no larger than 64 bytes
-                #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+                #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))]
                 const _: () = {
                     if mem::size_of::<Key<'static>>() > 64 {
                         panic!("{}", concat!(
@@ -353,7 +353,7 @@ macro_rules! define_callbacks {
                 };
 
                 // Ensure that values grow no larger than 64 bytes
-                #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+                #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))]
                 const _: () = {
                     if mem::size_of::<Value<'static>>() > 64 {
                         panic!("{}", concat!(
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 05f6fbbbfa3..f10b204cd47 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -12,7 +12,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{BindingAnnotation, ByRef, RangeEnd};
+use rustc_hir::{BindingAnnotation, ByRef, MatchSource, RangeEnd};
 use rustc_index::newtype_index;
 use rustc_index::IndexVec;
 use rustc_middle::middle::region;
@@ -358,6 +358,7 @@ pub enum ExprKind<'tcx> {
         scrutinee: ExprId,
         scrutinee_hir_id: hir::HirId,
         arms: Box<[ArmId]>,
+        match_source: MatchSource,
     },
     /// A block.
     Block {
@@ -1120,7 +1121,8 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                             printed += 1;
                         }
 
-                        if printed < variant.fields.len() {
+                        let is_union = self.ty.ty_adt_def().is_some_and(|adt| adt.is_union());
+                        if printed < variant.fields.len() && (!is_union || printed == 0) {
                             write!(f, "{}..", start_or_comma())?;
                         }
 
@@ -1204,7 +1206,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     // tidy-alphabetical-start
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index efea2a66bb2..ee816791919 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -550,7 +550,7 @@ impl<'tcx> ObligationCauseCode<'tcx> {
 }
 
 // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(ObligationCauseCode<'_>, 48);
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 8e9751f4529..c35524373c7 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -193,7 +193,6 @@ pub enum SelectionCandidate<'tcx> {
 /// The evaluation results are ordered:
 ///     - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
 ///       implies `EvaluatedToAmbig` implies `EvaluatedToAmbigStackDependent`
-///     - `EvaluatedToErr` implies `EvaluatedToErrStackDependent`
 ///     - the "union" of evaluation results is equal to their maximum -
 ///     all the "potential success" candidates can potentially succeed,
 ///     so they are noops when unioned with a definite error, and within
@@ -219,52 +218,9 @@ pub enum EvaluationResult {
     /// variables. We are somewhat imprecise there, so we don't actually
     /// know the real result.
     ///
-    /// This can't be trivially cached for the same reason as `EvaluatedToErrStackDependent`.
+    /// This can't be trivially cached because the result depends on the
+    /// stack results.
     EvaluatedToAmbigStackDependent,
-    /// Evaluation failed because we encountered an obligation we are already
-    /// trying to prove on this branch.
-    ///
-    /// We know this branch can't be a part of a minimal proof-tree for
-    /// the "root" of our cycle, because then we could cut out the recursion
-    /// and maintain a valid proof tree. However, this does not mean
-    /// that all the obligations on this branch do not hold -- it's possible
-    /// that we entered this branch "speculatively", and that there
-    /// might be some other way to prove this obligation that does not
-    /// go through this cycle -- so we can't cache this as a failure.
-    ///
-    /// For example, suppose we have this:
-    ///
-    /// ```rust,ignore (pseudo-Rust)
-    /// pub trait Trait { fn xyz(); }
-    /// // This impl is "useless", but we can still have
-    /// // an `impl Trait for SomeUnsizedType` somewhere.
-    /// impl<T: Trait + Sized> Trait for T { fn xyz() {} }
-    ///
-    /// pub fn foo<T: Trait + ?Sized>() {
-    ///     <T as Trait>::xyz();
-    /// }
-    /// ```
-    ///
-    /// When checking `foo`, we have to prove `T: Trait`. This basically
-    /// translates into this:
-    ///
-    /// ```plain,ignore
-    /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
-    /// ```
-    ///
-    /// When we try to prove it, we first go the first option, which
-    /// recurses. This shows us that the impl is "useless" -- it won't
-    /// tell us that `T: Trait` unless it already implemented `Trait`
-    /// by some other means. However, that does not prevent `T: Trait`
-    /// does not hold, because of the bound (which can indeed be satisfied
-    /// by `SomeUnsizedType` from another crate).
-    //
-    // FIXME: when an `EvaluatedToErrStackDependent` goes past its parent root, we
-    // ought to convert it to an `EvaluatedToErr`, because we know
-    // there definitely isn't a proof tree for that obligation. Not
-    // doing so is still sound -- there isn't any proof tree, so the
-    // branch still can't be a part of a minimal one -- but does not re-enable caching.
-    EvaluatedToErrStackDependent,
     /// Evaluation failed.
     EvaluatedToErr,
 }
@@ -290,13 +246,13 @@ impl EvaluationResult {
             | EvaluatedToAmbig
             | EvaluatedToAmbigStackDependent => true,
 
-            EvaluatedToErr | EvaluatedToErrStackDependent => false,
+            EvaluatedToErr => false,
         }
     }
 
     pub fn is_stack_dependent(self) -> bool {
         match self {
-            EvaluatedToAmbigStackDependent | EvaluatedToErrStackDependent => true,
+            EvaluatedToAmbigStackDependent => true,
 
             EvaluatedToOkModuloOpaqueTypes
             | EvaluatedToOk
diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
index 50d629120ab..c9fd20bc112 100644
--- a/compiler/rustc_middle/src/ty/cast.rs
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -83,9 +83,9 @@ pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKin
     let cast = CastTy::from_ty(cast_ty);
     let cast_kind = match (from, cast) {
         (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
-            mir::CastKind::PointerExposeAddress
+            mir::CastKind::PointerExposeProvenance
         }
-        (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerFromExposedAddress,
+        (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance,
         (_, Some(CastTy::DynStar)) => mir::CastKind::DynStar,
         (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt,
         (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr,
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index ddbc0bffaed..e7a1679b151 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -458,7 +458,6 @@ impl_decodable_via_ref! {
     &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
     &'tcx traits::ImplSource<'tcx, ()>,
     &'tcx mir::Body<'tcx>,
-    &'tcx mir::UnsafetyCheckResult,
     &'tcx mir::BorrowCheckResult<'tcx>,
     &'tcx mir::coverage::CodeRegion,
     &'tcx ty::List<ty::BoundVariableKind>,
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 3713883eb00..49b806b8369 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -59,7 +59,7 @@ pub struct ConstData<'tcx> {
     pub kind: ConstKind<'tcx>,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(ConstData<'_>, 40);
 
 impl<'tcx> Const<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index ea02faca5f3..94e41709f5d 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -71,8 +71,8 @@ pub enum Expr<'tcx> {
     Cast(CastKind, Const<'tcx>, Ty<'tcx>),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(Expr<'_>, 24);
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(super::ConstKind<'_>, 32);
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 188cb50849d..b8d68c1b8be 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -956,6 +956,13 @@ impl<'tcx> TyCtxt<'tcx> {
         self.get_lang_items(())
     }
 
+    /// Gets a `Ty` representing the [`LangItem::OrderingEnum`]
+    #[track_caller]
+    pub fn ty_ordering_enum(self, span: Option<Span>) -> Ty<'tcx> {
+        let ordering_enum = self.require_lang_item(hir::LangItem::OrderingEnum, span);
+        self.type_of(ordering_enum).no_bound_vars().unwrap()
+    }
+
     /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
     /// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
     pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {
@@ -1954,33 +1961,104 @@ impl<'tcx> TyCtxt<'tcx> {
         if pred.kind() != binder { self.mk_predicate(binder) } else { pred }
     }
 
-    #[inline(always)]
-    pub(crate) fn check_and_mk_args(
+    pub fn check_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) -> bool {
+        self.check_args_compatible_inner(def_id, args, false)
+    }
+
+    fn check_args_compatible_inner(
         self,
-        _def_id: DefId,
-        args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
-    ) -> GenericArgsRef<'tcx> {
-        let args = args.into_iter().map(Into::into);
-        #[cfg(debug_assertions)]
+        def_id: DefId,
+        args: &'tcx [ty::GenericArg<'tcx>],
+        nested: bool,
+    ) -> bool {
+        let generics = self.generics_of(def_id);
+
+        // IATs themselves have a weird arg setup (self + own args), but nested items *in* IATs
+        // (namely: opaques, i.e. ATPITs) do not.
+        let own_args = if !nested
+            && let DefKind::AssocTy = self.def_kind(def_id)
+            && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id))
         {
-            let generics = self.generics_of(_def_id);
+            if generics.params.len() + 1 != args.len() {
+                return false;
+            }
 
-            let n = if let DefKind::AssocTy = self.def_kind(_def_id)
-                && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(_def_id))
+            if !matches!(args[0].unpack(), ty::GenericArgKind::Type(_)) {
+                return false;
+            }
+
+            &args[1..]
+        } else {
+            if generics.count() != args.len() {
+                return false;
+            }
+
+            let (parent_args, own_args) = args.split_at(generics.parent_count);
+
+            if let Some(parent) = generics.parent
+                && !self.check_args_compatible_inner(parent, parent_args, true)
             {
-                // If this is an inherent projection.
-                generics.params.len() + 1
-            } else {
-                generics.count()
-            };
-            assert_eq!(
-                (n, Some(n)),
-                args.size_hint(),
-                "wrong number of generic parameters for {_def_id:?}: {:?}",
-                args.collect::<Vec<_>>(),
-            );
+                return false;
+            }
+
+            own_args
+        };
+
+        for (param, arg) in std::iter::zip(&generics.params, own_args) {
+            match (&param.kind, arg.unpack()) {
+                (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
+                | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
+                | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
+                _ => return false,
+            }
+        }
+
+        true
+    }
+
+    /// With `cfg(debug_assertions)`, assert that args are compatible with their generics,
+    /// and print out the args if not.
+    pub fn debug_assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) {
+        if cfg!(debug_assertions) {
+            if !self.check_args_compatible(def_id, args) {
+                if let DefKind::AssocTy = self.def_kind(def_id)
+                    && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id))
+                {
+                    bug!(
+                        "args not compatible with generics for {}: args={:#?}, generics={:#?}",
+                        self.def_path_str(def_id),
+                        args,
+                        // Make `[Self, GAT_ARGS...]` (this could be simplified)
+                        self.mk_args_from_iter(
+                            [self.types.self_param.into()].into_iter().chain(
+                                self.generics_of(def_id)
+                                    .own_args(ty::GenericArgs::identity_for_item(self, def_id))
+                                    .iter()
+                                    .copied()
+                            )
+                        )
+                    );
+                } else {
+                    bug!(
+                        "args not compatible with generics for {}: args={:#?}, generics={:#?}",
+                        self.def_path_str(def_id),
+                        args,
+                        ty::GenericArgs::identity_for_item(self, def_id)
+                    );
+                }
+            }
         }
-        self.mk_args_from_iter(args)
+    }
+
+    #[inline(always)]
+    pub(crate) fn check_and_mk_args(
+        self,
+        def_id: DefId,
+        args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
+    ) -> GenericArgsRef<'tcx> {
+        let args = self.mk_args_from_iter(args.into_iter().map(Into::into));
+        self.debug_assert_args_compatible(def_id, args);
+        args
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 4fec5653a79..4a7720b38f8 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -31,6 +31,28 @@ pub struct Instance<'tcx> {
     pub args: GenericArgsRef<'tcx>,
 }
 
+/// Describes why a `ReifyShim` was created. This is needed to distingish a ReifyShim created to
+/// adjust for things like `#[track_caller]` in a vtable from a `ReifyShim` created to produce a
+/// function pointer from a vtable entry.
+/// Currently, this is only used when KCFI is enabled, as only KCFI needs to treat those two
+/// `ReifyShim`s differently.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
+pub enum ReifyReason {
+    /// The `ReifyShim` was created to produce a function pointer. This happens when:
+    /// * A vtable entry is directly converted to a function call (e.g. creating a fn ptr from a
+    ///   method on a `dyn` object).
+    /// * A function with `#[track_caller]` is converted to a function pointer
+    /// * If KCFI is enabled, creating a function pointer from a method on an object-safe trait.
+    /// This includes the case of converting `::call`-like methods on closure-likes to function
+    /// pointers.
+    FnPtr,
+    /// This `ReifyShim` was created to populate a vtable. Currently, this happens when a
+    /// `#[track_caller]` mismatch occurs between the implementation of a method and the method.
+    /// This includes the case of `::call`-like methods in closure-likes' vtables.
+    Vtable,
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub enum InstanceDef<'tcx> {
@@ -67,7 +89,13 @@ pub enum InstanceDef<'tcx> {
     /// Because this is a required part of the function's ABI but can't be tracked
     /// as a property of the function pointer, we use a single "caller location"
     /// (the definition of the function itself).
-    ReifyShim(DefId),
+    ///
+    /// The second field encodes *why* this shim was created. This allows distinguishing between
+    /// a `ReifyShim` that appears in a vtable vs one that appears as a function pointer.
+    ///
+    /// This field will only be populated if we are compiling in a mode that needs these shims
+    /// to be separable, currently only when KCFI is enabled.
+    ReifyShim(DefId, Option<ReifyReason>),
 
     /// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers).
     ///
@@ -194,7 +222,7 @@ impl<'tcx> InstanceDef<'tcx> {
         match self {
             InstanceDef::Item(def_id)
             | InstanceDef::VTableShim(def_id)
-            | InstanceDef::ReifyShim(def_id)
+            | InstanceDef::ReifyShim(def_id, _)
             | InstanceDef::FnPtrShim(def_id, _)
             | InstanceDef::Virtual(def_id, _)
             | InstanceDef::Intrinsic(def_id)
@@ -354,7 +382,9 @@ fn fmt_instance(
     match instance.def {
         InstanceDef::Item(_) => Ok(()),
         InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"),
-        InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"),
+        InstanceDef::ReifyShim(_, None) => write!(f, " - shim(reify)"),
+        InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => write!(f, " - shim(reify-fnptr)"),
+        InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => write!(f, " - shim(reify-vtable)"),
         InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"),
         InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"),
         InstanceDef::Virtual(_, num) => write!(f, " - virtual#{num}"),
@@ -476,15 +506,34 @@ impl<'tcx> Instance<'tcx> {
         debug!("resolve(def_id={:?}, args={:?})", def_id, args);
         // Use either `resolve_closure` or `resolve_for_vtable`
         assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}");
+        let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr);
         Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
             match resolved.def {
                 InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => {
                     debug!(" => fn pointer created for function with #[track_caller]");
-                    resolved.def = InstanceDef::ReifyShim(def);
+                    resolved.def = InstanceDef::ReifyShim(def, reason);
                 }
                 InstanceDef::Virtual(def_id, _) => {
                     debug!(" => fn pointer created for virtual call");
-                    resolved.def = InstanceDef::ReifyShim(def_id);
+                    resolved.def = InstanceDef::ReifyShim(def_id, reason);
+                }
+                // Reify `Trait::method` implementations if KCFI is enabled
+                // FIXME(maurer) only reify it if it is a vtable-safe function
+                _ if tcx.sess.is_sanitizer_kcfi_enabled()
+                    && tcx.associated_item(def_id).trait_item_def_id.is_some() =>
+                {
+                    // If this function could also go in a vtable, we need to `ReifyShim` it with
+                    // KCFI because it can only attach one type per function.
+                    resolved.def = InstanceDef::ReifyShim(resolved.def_id(), reason)
+                }
+                // Reify `::call`-like method implementations if KCFI is enabled
+                _ if tcx.sess.is_sanitizer_kcfi_enabled()
+                    && tcx.is_closure_like(resolved.def_id()) =>
+                {
+                    // Reroute through a reify via the *unresolved* instance. The resolved one can't
+                    // be directly reified because it's closure-like. The reify can handle the
+                    // unresolved instance.
+                    resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args }
                 }
                 _ => {}
             }
@@ -508,6 +557,7 @@ impl<'tcx> Instance<'tcx> {
             debug!(" => associated item with unsizeable self: Self");
             Some(Instance { def: InstanceDef::VTableShim(def_id), args })
         } else {
+            let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable);
             Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
                 match resolved.def {
                     InstanceDef::Item(def) => {
@@ -544,18 +594,18 @@ impl<'tcx> Instance<'tcx> {
                                 // Create a shim for the `FnOnce/FnMut/Fn` method we are calling
                                 // - unlike functions, invoking a closure always goes through a
                                 // trait.
-                                resolved = Instance { def: InstanceDef::ReifyShim(def_id), args };
+                                resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args };
                             } else {
                                 debug!(
                                     " => vtable fn pointer created for function with #[track_caller]: {:?}", def
                                 );
-                                resolved.def = InstanceDef::ReifyShim(def);
+                                resolved.def = InstanceDef::ReifyShim(def, reason);
                             }
                         }
                     }
                     InstanceDef::Virtual(def_id, _) => {
                         debug!(" => vtable fn pointer created for virtual call");
-                        resolved.def = InstanceDef::ReifyShim(def_id);
+                        resolved.def = InstanceDef::ReifyShim(def_id, reason)
                     }
                     _ => {}
                 }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 99da981b9d6..fb56c71c517 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -88,7 +88,7 @@ pub use self::context::{
     tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift,
     TyCtxt, TyCtxtFeed,
 };
-pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams};
+pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams};
 pub use self::list::List;
 pub use self::parameterized::ParameterizedOverTcx;
 pub use self::predicate::{
@@ -1034,9 +1034,11 @@ impl PlaceholderLike for PlaceholderConst {
     }
 }
 
-/// When type checking, we use the `ParamEnv` to track
-/// details about the set of where-clauses that are in scope at this
-/// particular point.
+/// When interacting with the type system we must provide information about the
+/// environment. `ParamEnv` is the type that represents this information. See the
+/// [dev guide chapter][param_env_guide] for more information.
+///
+/// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html
 #[derive(Copy, Clone, Hash, PartialEq, Eq)]
 pub struct ParamEnv<'tcx> {
     /// This packs both caller bounds and the reveal enum into one pointer.
@@ -1103,8 +1105,11 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ParamEnv<'tcx> {
 impl<'tcx> ParamEnv<'tcx> {
     /// Construct a trait environment suitable for contexts where
     /// there are no where-clauses in scope. Hidden types (like `impl
-    /// Trait`) are left hidden, so this is suitable for ordinary
-    /// type-checking.
+    /// Trait`) are left hidden. In majority of cases it is incorrect
+    /// to use an empty environment. See the [dev guide section][param_env_guide]
+    /// for information on what a `ParamEnv` is and how to acquire one.
+    ///
+    /// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html
     #[inline]
     pub fn empty() -> Self {
         Self::new(List::empty(), Reveal::UserFacing)
@@ -1319,7 +1324,7 @@ impl VariantDef {
     pub fn single_field(&self) -> &FieldDef {
         assert!(self.fields.len() == 1);
 
-        &self.fields[FieldIdx::from_u32(0)]
+        &self.fields[FieldIdx::ZERO]
     }
 
     /// Returns the last field in this variant, if present.
@@ -1552,7 +1557,6 @@ impl<'tcx> TyCtxt<'tcx> {
                     attr::ReprRust => ReprFlags::empty(),
                     attr::ReprC => ReprFlags::IS_C,
                     attr::ReprPacked(pack) => {
-                        let pack = Align::from_bytes(pack as u64).unwrap();
                         min_pack = Some(if let Some(min_pack) = min_pack {
                             min_pack.min(pack)
                         } else {
@@ -1584,7 +1588,7 @@ impl<'tcx> TyCtxt<'tcx> {
                         ReprFlags::empty()
                     }
                     attr::ReprAlign(align) => {
-                        max_align = max_align.max(Some(Align::from_bytes(align as u64).unwrap()));
+                        max_align = max_align.max(Some(align));
                         ReprFlags::empty()
                     }
                 });
@@ -2164,7 +2168,7 @@ pub struct DestructuredConst<'tcx> {
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 5ff98dc8c87..2a898430ce9 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2589,7 +2589,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
                     ty::BrAnon | ty::BrEnv => r,
                     _ => {
                         // Index doesn't matter, since this is just for naming and these never get bound
-                        let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
+                        let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind };
                         *self
                             .region_map
                             .entry(br)
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 867faf63261..b92800a1728 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -140,6 +140,10 @@ impl<'tcx> rustc_type_ir::new::Region<TyCtxt<'tcx>> for Region<'tcx> {
     fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
         Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon })
     }
+
+    fn new_static(tcx: TyCtxt<'tcx>) -> Self {
+        tcx.lifetimes.re_static
+    }
 }
 
 /// Region utilities
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index a62379def53..0e7010e67d7 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -449,6 +449,7 @@ TrivialTypeTraversalAndLiftImpls! {
     crate::ty::ClosureKind,
     crate::ty::ParamConst,
     crate::ty::ParamTy,
+    crate::ty::instance::ReifyReason,
     interpret::AllocId,
     interpret::CtfeProvenance,
     interpret::Scalar,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 57a675e4453..2ab63f01e7c 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -11,7 +11,7 @@ use crate::ty::{
 };
 use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use crate::ty::{List, ParamEnv};
-use hir::def::DefKind;
+use hir::def::{CtorKind, DefKind};
 use rustc_data_structures::captures::Captures;
 use rustc_errors::{DiagArgValue, ErrorGuaranteed, IntoDiagArg, MultiSpan};
 use rustc_hir as hir;
@@ -1624,6 +1624,7 @@ impl<'tcx> Ty<'tcx> {
 
     #[inline]
     pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
+        tcx.debug_assert_args_compatible(def.did(), args);
         Ty::new(tcx, Adt(def, args))
     }
 
@@ -1670,6 +1671,10 @@ impl<'tcx> Ty<'tcx> {
         def_id: DefId,
         args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
     ) -> Ty<'tcx> {
+        debug_assert_matches!(
+            tcx.def_kind(def_id),
+            DefKind::AssocFn | DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn)
+        );
         let args = tcx.check_and_mk_args(def_id, args);
         Ty::new(tcx, FnDef(def_id, args))
     }
@@ -1704,11 +1709,7 @@ impl<'tcx> Ty<'tcx> {
         def_id: DefId,
         closure_args: GenericArgsRef<'tcx>,
     ) -> Ty<'tcx> {
-        debug_assert_eq!(
-            closure_args.len(),
-            tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3,
-            "closure constructed with incorrect generic parameters"
-        );
+        tcx.debug_assert_args_compatible(def_id, closure_args);
         Ty::new(tcx, Closure(def_id, closure_args))
     }
 
@@ -1718,11 +1719,7 @@ impl<'tcx> Ty<'tcx> {
         def_id: DefId,
         closure_args: GenericArgsRef<'tcx>,
     ) -> Ty<'tcx> {
-        debug_assert_eq!(
-            closure_args.len(),
-            tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5,
-            "closure constructed with incorrect generic parameters"
-        );
+        tcx.debug_assert_args_compatible(def_id, closure_args);
         Ty::new(tcx, CoroutineClosure(def_id, closure_args))
     }
 
@@ -1732,11 +1729,7 @@ impl<'tcx> Ty<'tcx> {
         def_id: DefId,
         coroutine_args: GenericArgsRef<'tcx>,
     ) -> Ty<'tcx> {
-        debug_assert_eq!(
-            coroutine_args.len(),
-            tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6,
-            "coroutine constructed with incorrect number of generic parameters"
-        );
+        tcx.debug_assert_args_compatible(def_id, coroutine_args);
         Ty::new(tcx, Coroutine(def_id, coroutine_args))
     }
 
@@ -1947,7 +1940,7 @@ impl<'tcx> Ty<'tcx> {
             Adt(def, args) => {
                 assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type");
                 let variant = def.non_enum_variant();
-                let f0_ty = variant.fields[FieldIdx::from_u32(0)].ty(tcx, args);
+                let f0_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args);
 
                 match f0_ty.kind() {
                     // If the first field is an array, we assume it is the only field and its
@@ -2692,7 +2685,7 @@ impl<'tcx> VarianceDiagInfo<'tcx> {
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index d60926bf796..0d74524276f 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -19,7 +19,7 @@ use rustc_hir::{
     hir_id::OwnerId,
     BindingAnnotation, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability,
 };
-use rustc_index::{Idx, IndexVec};
+use rustc_index::IndexVec;
 use rustc_macros::HashStable;
 use rustc_middle::mir::FakeReadCause;
 use rustc_session::Session;
@@ -680,7 +680,7 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
                     return false;
                 }
 
-                iter::zip(user_args.args, BoundVar::new(0)..).all(|(kind, cvar)| {
+                iter::zip(user_args.args, BoundVar::ZERO..).all(|(kind, cvar)| {
                     match kind.unpack() {
                         GenericArgKind::Type(ty) => match ty.kind() {
                             ty::Bound(debruijn, b) => {
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 6200f4bda6b..00e99f330f7 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -13,31 +13,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         ast_block: BlockId,
         source_info: SourceInfo,
     ) -> BlockAnd<()> {
-        let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode } =
+        let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode: _ } =
             self.thir[ast_block];
         self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
             if targeted_by_break {
                 this.in_breakable_scope(None, destination, span, |this| {
-                    Some(this.ast_block_stmts(
-                        destination,
-                        block,
-                        span,
-                        stmts,
-                        expr,
-                        safety_mode,
-                        region_scope,
-                    ))
+                    Some(this.ast_block_stmts(destination, block, span, stmts, expr, region_scope))
                 })
             } else {
-                this.ast_block_stmts(
-                    destination,
-                    block,
-                    span,
-                    stmts,
-                    expr,
-                    safety_mode,
-                    region_scope,
-                )
+                this.ast_block_stmts(destination, block, span, stmts, expr, region_scope)
             }
         })
     }
@@ -49,7 +33,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         span: Span,
         stmts: &[StmtId],
         expr: Option<ExprId>,
-        safety_mode: BlockSafety,
         region_scope: Scope,
     ) -> BlockAnd<()> {
         let this = self;
@@ -72,13 +55,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // First we build all the statements in the block.
         let mut let_scope_stack = Vec::with_capacity(8);
         let outer_source_scope = this.source_scope;
-        let outer_in_scope_unsafe = this.in_scope_unsafe;
         // This scope information is kept for breaking out of the parent remainder scope in case
         // one let-else pattern matching fails.
         // By doing so, we can be sure that even temporaries that receive extended lifetime
         // assignments are dropped, too.
         let mut last_remainder_scope = region_scope;
-        this.update_source_scope_for_safety_mode(span, safety_mode);
 
         let source_info = this.source_info(span);
         for stmt in stmts {
@@ -202,7 +183,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let_scope_stack.push(remainder_scope);
 
                     let visibility_scope =
-                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
+                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited));
 
                     let initializer_span = this.thir[*initializer].span;
                     let scope = (*init_scope, source_info);
@@ -271,7 +252,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree);
 
                     let visibility_scope =
-                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
+                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited));
 
                     // Evaluate the initializer, if present.
                     if let Some(init) = *initializer {
@@ -364,22 +345,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
         // Restore the original source scope.
         this.source_scope = outer_source_scope;
-        this.in_scope_unsafe = outer_in_scope_unsafe;
         block.unit()
     }
-
-    /// If we are entering an unsafe block, create a new source scope
-    fn update_source_scope_for_safety_mode(&mut self, span: Span, safety_mode: BlockSafety) {
-        debug!("update_source_scope_for({:?}, {:?})", span, safety_mode);
-        let new_unsafety = match safety_mode {
-            BlockSafety::Safe => return,
-            BlockSafety::BuiltinUnsafe => Safety::BuiltinUnsafe,
-            BlockSafety::ExplicitUnsafe(hir_id) => {
-                self.in_scope_unsafe = Safety::ExplicitUnsafe(hir_id);
-                Safety::ExplicitUnsafe(hir_id)
-            }
-        };
-
-        self.source_scope = self.new_source_scope(span, LintLevel::Inherited, Some(new_unsafety));
-    }
 }
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index 0475bb8908b..30877e38318 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -72,10 +72,7 @@ pub(super) fn build_custom_mir<'tcx>(
         parent_scope: None,
         inlined: None,
         inlined_parent_scope: None,
-        local_data: ClearCrossCrate::Set(SourceScopeLocalData {
-            lint_root: hir_id,
-            safety: Safety::Safe,
-        }),
+        local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }),
     });
     body.injection_phase = Some(parse_attribute(attr));
 
diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs
index a6f9caada2d..0384b9bc154 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse.rs
@@ -215,7 +215,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
 
     fn parse_local_decls(&mut self, mut stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
         let (ret_var, ..) = self.parse_let_statement(stmts.next().unwrap())?;
-        self.local_map.insert(ret_var, Local::from_u32(0));
+        self.local_map.insert(ret_var, Local::ZERO);
 
         for stmt in stmts {
             let (var, ty, span) = self.parse_let_statement(stmt)?;
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index c77f4a06d05..260ab058e60 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -118,19 +118,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             ExprKind::Box { value } => {
                 let value_ty = this.thir[value].ty;
                 let tcx = this.tcx;
-
-                // `exchange_malloc` is unsafe but box is safe, so need a new scope.
-                let synth_scope = this.new_source_scope(
-                    expr_span,
-                    LintLevel::Inherited,
-                    Some(Safety::BuiltinUnsafe),
-                );
-                let synth_info = SourceInfo { span: expr_span, scope: synth_scope };
+                let source_info = this.source_info(expr_span);
 
                 let size = this.temp(tcx.types.usize, expr_span);
                 this.cfg.push_assign(
                     block,
-                    synth_info,
+                    source_info,
                     size,
                     Rvalue::NullaryOp(NullOp::SizeOf, value_ty),
                 );
@@ -138,7 +131,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let align = this.temp(tcx.types.usize, expr_span);
                 this.cfg.push_assign(
                     block,
-                    synth_info,
+                    source_info,
                     align,
                     Rvalue::NullaryOp(NullOp::AlignOf, value_ty),
                 );
@@ -154,7 +147,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let success = this.cfg.start_new_block();
                 this.cfg.terminate(
                     block,
-                    synth_info,
+                    source_info,
                     TerminatorKind::Call {
                         func: exchange_malloc,
                         args: vec![
@@ -580,7 +573,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     result_value,
                     Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))),
                 );
-                let val_fld = FieldIdx::new(0);
+                let val_fld = FieldIdx::ZERO;
                 let of_fld = FieldIdx::new(1);
 
                 let tcx = self.tcx;
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index b4eeeccc127..c8360b6a5fd 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -69,7 +69,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         // FIXME: Does this need extra logic to handle let-chains?
                         let source_info = if this.is_let(cond) {
                             let variable_scope =
-                                this.new_source_scope(then_span, LintLevel::Inherited, None);
+                                this.new_source_scope(then_span, LintLevel::Inherited);
                             this.source_scope = variable_scope;
                             SourceInfo { span: then_span, scope: variable_scope }
                         } else {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index b4c98834d0a..367c391b45a 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -214,12 +214,77 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ///
     /// ## False edges
     ///
-    /// We don't want to have the exact structure of the decision tree be
-    /// visible through borrow checking. False edges ensure that the CFG as
-    /// seen by borrow checking doesn't encode this. False edges are added:
+    /// We don't want to have the exact structure of the decision tree be visible through borrow
+    /// checking. Specifically we want borrowck to think that:
+    /// - at any point, any or none of the patterns and guards seen so far may have been tested;
+    /// - after the match, any of the patterns may have matched.
     ///
-    /// * From each pre-binding block to the next pre-binding block.
-    /// * From each otherwise block to the next pre-binding block.
+    /// For example, all of these would fail to error if borrowck could see the real CFG (examples
+    /// taken from `tests/ui/nll/match-cfg-fake-edges.rs`):
+    /// ```ignore (too many errors, this is already in the test suite)
+    /// let x = String::new();
+    /// let _ = match true {
+    ///     _ => {},
+    ///     _ => drop(x),
+    /// };
+    /// // Borrowck must not know the second arm is never run.
+    /// drop(x); //~ ERROR use of moved value
+    ///
+    /// let x;
+    /// # let y = true;
+    /// match y {
+    ///     _ if { x = 2; true } => {},
+    ///     // Borrowck must not know the guard is always run.
+    ///     _ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized
+    /// };
+    ///
+    /// let x = String::new();
+    /// # let y = true;
+    /// match y {
+    ///     false if { drop(x); true } => {},
+    ///     // Borrowck must not know the guard is not run in the `true` case.
+    ///     true => drop(x), //~ ERROR use of moved value: `x`
+    ///     false => {},
+    /// };
+    ///
+    /// # let mut y = (true, true);
+    /// let r = &mut y.1;
+    /// match y {
+    ///     //~^ ERROR cannot use `y.1` because it was mutably borrowed
+    ///     (false, true) => {}
+    ///     // Borrowck must not know we don't test `y.1` when `y.0` is `true`.
+    ///     (true, _) => drop(r),
+    ///     (false, _) => {}
+    /// };
+    /// ```
+    ///
+    /// We add false edges to act as if we were naively matching each arm in order. What we need is
+    /// a (fake) path from each candidate to the next, specifically from candidate C's pre-binding
+    /// block to next candidate D's pre-binding block. For maximum precision (needed for deref
+    /// patterns), we choose the earliest node on D's success path that doesn't also lead to C (to
+    /// avoid loops).
+    ///
+    /// This turns out to be easy to compute: that block is the `start_block` of the first call to
+    /// `match_candidates` where D is the first candidate in the list.
+    ///
+    /// For example:
+    /// ```rust
+    /// # let (x, y) = (true, true);
+    /// match (x, y) {
+    ///   (true, true) => 1,
+    ///   (false, true) => 2,
+    ///   (true, false) => 3,
+    ///   _ => 4,
+    /// }
+    /// # ;
+    /// ```
+    /// In this example, the pre-binding block of arm 1 has a false edge to the block for result
+    /// `false` of the first test on `x`. The other arms have false edges to the pre-binding blocks
+    /// of the next arm.
+    ///
+    /// On top of this, we also add a false edge from the otherwise_block of each guard to the
+    /// aforementioned start block of the next candidate, to ensure borrock doesn't rely on which
+    /// guards may have run.
     #[instrument(level = "debug", skip(self, arms))]
     pub(crate) fn match_expr(
         &mut self,
@@ -365,7 +430,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         for candidate in candidates {
             candidate.visit_leaves(|leaf_candidate| {
                 if let Some(ref mut prev) = previous_candidate {
-                    prev.next_candidate_pre_binding_block = leaf_candidate.pre_binding_block;
+                    assert!(leaf_candidate.false_edge_start_block.is_some());
+                    prev.next_candidate_start_block = leaf_candidate.false_edge_start_block;
                 }
                 previous_candidate = Some(leaf_candidate);
             });
@@ -732,7 +798,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             &mut |this, name, mode, var, span, ty, user_ty| {
                 if visibility_scope.is_none() {
                     visibility_scope =
-                        Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
+                        Some(this.new_source_scope(scope_span, LintLevel::Inherited));
                 }
                 let source_info = SourceInfo { span, scope: this.source_scope };
                 let visibility_scope = visibility_scope.unwrap();
@@ -1010,8 +1076,12 @@ struct Candidate<'pat, 'tcx> {
 
     /// The block before the `bindings` have been established.
     pre_binding_block: Option<BasicBlock>,
-    /// The pre-binding block of the next candidate.
-    next_candidate_pre_binding_block: Option<BasicBlock>,
+
+    /// The earliest block that has only candidates >= this one as descendents. Used for false
+    /// edges, see the doc for [`Builder::match_expr`].
+    false_edge_start_block: Option<BasicBlock>,
+    /// The `false_edge_start_block` of the next candidate.
+    next_candidate_start_block: Option<BasicBlock>,
 }
 
 impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
@@ -1033,7 +1103,8 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
             or_span: None,
             otherwise_block: None,
             pre_binding_block: None,
-            next_candidate_pre_binding_block: None,
+            false_edge_start_block: None,
+            next_candidate_start_block: None,
         }
     }
 
@@ -1270,9 +1341,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ) {
         let mut split_or_candidate = false;
         for candidate in &mut *candidates {
-            if let [MatchPair { test_case: TestCase::Or { pats, .. }, .. }] =
-                &*candidate.match_pairs
-            {
+            if let [MatchPair { test_case: TestCase::Or { .. }, .. }] = &*candidate.match_pairs {
                 // Split a candidate in which the only match-pair is an or-pattern into multiple
                 // candidates. This is so that
                 //
@@ -1282,9 +1351,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // }
                 //
                 // only generates a single switch.
-                candidate.subcandidates = self.create_or_subcandidates(pats, candidate.has_guard);
-                let first_match_pair = candidate.match_pairs.pop().unwrap();
-                candidate.or_span = Some(first_match_pair.pattern.span);
+                let match_pair = candidate.match_pairs.pop().unwrap();
+                self.create_or_subcandidates(candidate, match_pair);
                 split_or_candidate = true;
             }
         }
@@ -1297,7 +1365,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 for candidate in candidates.iter_mut() {
                     candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate));
                 }
-                self.match_simplified_candidates(
+                self.match_candidates(
                     span,
                     scrutinee_span,
                     start_block,
@@ -1328,6 +1396,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         otherwise_block: BasicBlock,
         candidates: &mut [&mut Candidate<'_, 'tcx>],
     ) {
+        if let [first, ..] = candidates {
+            if first.false_edge_start_block.is_none() {
+                first.false_edge_start_block = Some(start_block);
+            }
+        }
+
         match candidates {
             [] => {
                 // If there are no candidates that still need testing, we're done. Since all matches are
@@ -1472,14 +1546,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             return;
         }
 
-        let match_pairs = mem::take(&mut first_candidate.match_pairs);
-        let (first_match_pair, remaining_match_pairs) = match_pairs.split_first().unwrap();
-        let TestCase::Or { ref pats } = &first_match_pair.test_case else { unreachable!() };
-
+        let first_match_pair = first_candidate.match_pairs.remove(0);
+        let remaining_match_pairs = mem::take(&mut first_candidate.match_pairs);
         let remainder_start = self.cfg.start_new_block();
-        let or_span = first_match_pair.pattern.span;
         // Test the alternatives of this or-pattern.
-        self.test_or_pattern(first_candidate, start_block, remainder_start, pats, or_span);
+        self.test_or_pattern(first_candidate, start_block, remainder_start, first_match_pair);
 
         if !remaining_match_pairs.is_empty() {
             // If more match pairs remain, test them after each subcandidate.
@@ -1514,25 +1585,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         );
     }
 
-    #[instrument(
-        skip(self, start_block, otherwise_block, or_span, candidate, pats),
-        level = "debug"
-    )]
+    #[instrument(skip(self, start_block, otherwise_block, candidate, match_pair), level = "debug")]
     fn test_or_pattern<'pat>(
         &mut self,
         candidate: &mut Candidate<'pat, 'tcx>,
         start_block: BasicBlock,
         otherwise_block: BasicBlock,
-        pats: &[FlatPat<'pat, 'tcx>],
-        or_span: Span,
+        match_pair: MatchPair<'pat, 'tcx>,
     ) {
-        debug!("candidate={:#?}\npats={:#?}", candidate, pats);
-        let mut or_candidates: Vec<_> = pats
-            .iter()
-            .cloned()
-            .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
-            .collect();
-        let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect();
+        let or_span = match_pair.pattern.span;
+        self.create_or_subcandidates(candidate, match_pair);
+        let mut or_candidate_refs: Vec<_> = candidate.subcandidates.iter_mut().collect();
         self.match_candidates(
             or_span,
             or_span,
@@ -1540,34 +1603,49 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             otherwise_block,
             &mut or_candidate_refs,
         );
-        candidate.subcandidates = or_candidates;
-        candidate.or_span = Some(or_span);
         self.merge_trivial_subcandidates(candidate);
     }
 
-    /// Try to merge all of the subcandidates of the given candidate into one.
-    /// This avoids exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`.
+    /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
+    /// subcandidate. Any candidate that has been expanded that way should be passed to
+    /// `merge_trivial_subcandidates` after its subcandidates have been processed.
+    fn create_or_subcandidates<'pat>(
+        &mut self,
+        candidate: &mut Candidate<'pat, 'tcx>,
+        match_pair: MatchPair<'pat, 'tcx>,
+    ) {
+        let TestCase::Or { pats } = match_pair.test_case else { bug!() };
+        debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats);
+        candidate.or_span = Some(match_pair.pattern.span);
+        candidate.subcandidates = pats
+            .into_vec()
+            .into_iter()
+            .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
+            .collect();
+        candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block;
+    }
+
+    /// Try to merge all of the subcandidates of the given candidate into one. This avoids
+    /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The or-pattern should have
+    /// been expanded with `create_or_subcandidates`.
     fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
         if candidate.subcandidates.is_empty() || candidate.has_guard {
             // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
             return;
         }
 
-        let mut can_merge = true;
-
-        // Not `Iterator::all` because we don't want to short-circuit.
-        for subcandidate in &mut candidate.subcandidates {
-            self.merge_trivial_subcandidates(subcandidate);
-
-            // FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
-            can_merge &=
-                subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty();
-        }
-
+        // FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
+        let can_merge = candidate.subcandidates.iter().all(|subcandidate| {
+            subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty()
+        });
         if can_merge {
             let any_matches = self.cfg.start_new_block();
             let or_span = candidate.or_span.take().unwrap();
             let source_info = self.source_info(or_span);
+            if candidate.false_edge_start_block.is_none() {
+                candidate.false_edge_start_block =
+                    candidate.subcandidates[0].false_edge_start_block;
+            }
             for subcandidate in mem::take(&mut candidate.subcandidates) {
                 let or_block = subcandidate.pre_binding_block.unwrap();
                 self.cfg.goto(or_block, source_info, any_matches);
@@ -1593,10 +1671,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// [`Switch`]: TestKind::Switch
     /// [`SwitchInt`]: TestKind::SwitchInt
     /// [`Range`]: TestKind::Range
-    fn pick_test(
-        &mut self,
-        candidates: &mut [&mut Candidate<'_, 'tcx>],
-    ) -> (Place<'tcx>, Test<'tcx>) {
+    fn pick_test(&mut self, candidates: &[&mut Candidate<'_, 'tcx>]) -> (Place<'tcx>, Test<'tcx>) {
         // Extract the match-pair from the highest priority candidate
         let match_pair = &candidates.first().unwrap().match_pairs[0];
         let test = self.test(match_pair);
@@ -1986,12 +2061,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let mut block = candidate.pre_binding_block.unwrap();
 
-        if candidate.next_candidate_pre_binding_block.is_some() {
+        if candidate.next_candidate_start_block.is_some() {
             let fresh_block = self.cfg.start_new_block();
             self.false_edges(
                 block,
                 fresh_block,
-                candidate.next_candidate_pre_binding_block,
+                candidate.next_candidate_start_block,
                 candidate_source_info,
             );
             block = fresh_block;
@@ -2139,7 +2214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             self.false_edges(
                 otherwise_post_guard_block,
                 otherwise_block,
-                candidate.next_candidate_pre_binding_block,
+                candidate.next_candidate_start_block,
                 source_info,
             );
 
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index bf1906f370b..90f12e55ff4 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -12,7 +12,7 @@
 //! sort of test: for example, testing which variant an enum is, or
 //! testing a value against a constant.
 
-use crate::build::matches::{Candidate, FlatPat, MatchPair, PatternExtraData, TestCase};
+use crate::build::matches::{MatchPair, PatternExtraData, TestCase};
 use crate::build::Builder;
 
 use std::mem;
@@ -66,27 +66,4 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. }));
         debug!(simplified = ?match_pairs, "simplify_match_pairs");
     }
-
-    /// Create a new candidate for each pattern in `pats`, and recursively simplify tje
-    /// single-or-pattern case.
-    pub(super) fn create_or_subcandidates<'pat>(
-        &mut self,
-        pats: &[FlatPat<'pat, 'tcx>],
-        has_guard: bool,
-    ) -> Vec<Candidate<'pat, 'tcx>> {
-        pats.iter()
-            .cloned()
-            .map(|flat_pat| {
-                let mut candidate = Candidate::from_flat_pat(flat_pat, has_guard);
-                if let [MatchPair { test_case: TestCase::Or { pats, .. }, .. }] =
-                    &*candidate.match_pairs
-                {
-                    candidate.subcandidates = self.create_or_subcandidates(pats, has_guard);
-                    let first_match_pair = candidate.match_pairs.pop().unwrap();
-                    candidate.or_span = Some(first_match_pair.pattern.span);
-                }
-                candidate
-            })
-            .collect()
-    }
 }
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index b66dd83b7ec..690879b9488 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -650,12 +650,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
             }
 
-            // FIXME(#29623): return `Some(1)` when the values are different.
-            (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val })
-                if test_val == case_val =>
-            {
-                fully_matched = true;
-                Some(TestBranch::Success)
+            (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) => {
+                if test_val == case_val {
+                    fully_matched = true;
+                    Some(TestBranch::Success)
+                } else {
+                    fully_matched = false;
+                    Some(TestBranch::Failure)
+                }
             }
 
             (
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 274edf358e0..6972bc00e0b 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -66,17 +66,10 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx
             // maybe move the check to a MIR pass?
             tcx.ensure().check_liveness(def);
 
-            if tcx.sess.opts.unstable_opts.thir_unsafeck {
-                // Don't steal here if THIR unsafeck is being used. Instead
-                // steal in unsafeck. This is so that pattern inline constants
-                // can be evaluated as part of building the THIR of the parent
-                // function without a cycle.
-                build_mir(&thir.borrow())
-            } else {
-                // We ran all queries that depended on THIR at the beginning
-                // of `mir_build`, so now we can steal it
-                build_mir(&thir.steal())
-            }
+            // Don't steal here, instead steal in unsafeck. This is so that
+            // pattern inline constants can be evaluated as part of building the
+            // THIR of the parent function without a cycle.
+            build_mir(&thir.borrow())
         }
     };
 
@@ -190,9 +183,6 @@ struct Builder<'a, 'tcx> {
     /// `{ STMTS; EXPR1 } + EXPR2`.
     block_context: BlockContext,
 
-    /// The current unsafe block in scope
-    in_scope_unsafe: Safety,
-
     /// The vector of all scopes that we have created thus far;
     /// we track this for debuginfo later.
     source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
@@ -470,11 +460,6 @@ fn construct_fn<'tcx>(
         .output
         .span();
 
-    let safety = match fn_sig.unsafety {
-        hir::Unsafety::Normal => Safety::Safe,
-        hir::Unsafety::Unsafe => Safety::FnUnsafe,
-    };
-
     let mut abi = fn_sig.abi;
     if let DefKind::Closure = tcx.def_kind(fn_def) {
         // HACK(eddyb) Avoid having RustCall on closures,
@@ -520,7 +505,6 @@ fn construct_fn<'tcx>(
         fn_id,
         span_with_body,
         arguments.len(),
-        safety,
         return_ty,
         return_ty_span,
         coroutine,
@@ -590,18 +574,8 @@ fn construct_const<'a, 'tcx>(
     };
 
     let infcx = tcx.infer_ctxt().build();
-    let mut builder = Builder::new(
-        thir,
-        infcx,
-        def,
-        hir_id,
-        span,
-        0,
-        Safety::Safe,
-        const_ty,
-        const_ty_span,
-        None,
-    );
+    let mut builder =
+        Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None);
 
     let mut block = START_BLOCK;
     unpack!(block = builder.expr_into_dest(Place::return_place(), block, expr));
@@ -723,10 +697,7 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -
         parent_scope: None,
         inlined: None,
         inlined_parent_scope: None,
-        local_data: ClearCrossCrate::Set(SourceScopeLocalData {
-            lint_root: hir_id,
-            safety: Safety::Safe,
-        }),
+        local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }),
     });
 
     cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
@@ -753,7 +724,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         hir_id: hir::HirId,
         span: Span,
         arg_count: usize,
-        safety: Safety,
         return_ty: Ty<'tcx>,
         return_span: Span,
         coroutine: Option<Box<CoroutineInfo<'tcx>>>,
@@ -795,7 +765,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             guard_context: vec![],
             fixed_temps: Default::default(),
             fixed_temps_scope: None,
-            in_scope_unsafe: safety,
             local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1),
             canonical_user_type_annotations: IndexVec::new(),
             upvars: CaptureMap::new(),
@@ -807,10 +776,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         };
 
         assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
-        assert_eq!(
-            builder.new_source_scope(span, lint_level, Some(safety)),
-            OUTERMOST_SOURCE_SCOPE
-        );
+        assert_eq!(builder.new_source_scope(span, lint_level), OUTERMOST_SOURCE_SCOPE);
         builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None;
 
         builder
@@ -1024,7 +990,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             .as_ref()
             .assert_crate_local()
             .lint_root;
-        self.maybe_new_source_scope(pattern_span, None, arg_hir_id, parent_id);
+        self.maybe_new_source_scope(pattern_span, arg_hir_id, parent_id);
     }
 
     fn get_unit_temp(&mut self) -> Place<'tcx> {
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index aef63896dde..2d31e84aba7 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -190,7 +190,7 @@ rustc_index::newtype_index! {
     struct DropIdx {}
 }
 
-const ROOT_NODE: DropIdx = DropIdx::from_u32(0);
+const ROOT_NODE: DropIdx = DropIdx::ZERO;
 
 /// A tree of drops that we have deferred lowering. It's used for:
 ///
@@ -578,7 +578,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         if let LintLevel::Explicit(current_hir_id) = lint_level {
             let parent_id =
                 self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root;
-            self.maybe_new_source_scope(region_scope.1.span, None, current_hir_id, parent_id);
+            self.maybe_new_source_scope(region_scope.1.span, current_hir_id, parent_id);
         }
         self.push_scope(region_scope);
         let mut block;
@@ -767,7 +767,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn maybe_new_source_scope(
         &mut self,
         span: Span,
-        safety: Option<Safety>,
         current_id: HirId,
         parent_id: HirId,
     ) {
@@ -797,7 +796,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         if current_root != parent_root {
             let lint_level = LintLevel::Explicit(current_root);
-            self.source_scope = self.new_source_scope(span, lint_level, safety);
+            self.source_scope = self.new_source_scope(span, lint_level);
         }
     }
 
@@ -846,18 +845,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     }
 
     /// Creates a new source scope, nested in the current one.
-    pub(crate) fn new_source_scope(
-        &mut self,
-        span: Span,
-        lint_level: LintLevel,
-        safety: Option<Safety>,
-    ) -> SourceScope {
+    pub(crate) fn new_source_scope(&mut self, span: Span, lint_level: LintLevel) -> SourceScope {
         let parent = self.source_scope;
         debug!(
-            "new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}",
+            "new_source_scope({:?}, {:?}) - parent({:?})={:?}",
             span,
             lint_level,
-            safety,
             parent,
             self.source_scopes.get(parent)
         );
@@ -867,9 +860,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             } else {
                 self.source_scopes[parent].local_data.as_ref().assert_crate_local().lint_root
             },
-            safety: safety.unwrap_or_else(|| {
-                self.source_scopes[parent].local_data.as_ref().assert_crate_local().safety
-            }),
         };
         self.source_scopes.push(SourceScopeData {
             span,
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 07dc332b791..8aa9a75d96a 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -909,11 +909,6 @@ impl UnsafeOpKind {
 }
 
 pub fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
-    // THIR unsafeck can be disabled with `-Z thir-unsafeck=off`
-    if !tcx.sess.opts.unstable_opts.thir_unsafeck {
-        return;
-    }
-
     // Closures and inline consts are handled by their owner, if it has a body
     // Also, don't safety check custom MIR
     if tcx.is_typeck_child(def.to_def_id()) || tcx.has_attr(def, sym::custom_mir) {
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 848da56f981..26f10fdd333 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -456,8 +456,8 @@ pub enum UnusedUnsafeEnclosing {
 
 pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
     pub cx: &'m RustcPatCtxt<'p, 'tcx>,
-    pub expr_span: Span,
-    pub span: Span,
+    pub scrut_span: Span,
+    pub braces_span: Option<Span>,
     pub ty: Ty<'tcx>,
 }
 
@@ -465,7 +465,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo
     fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'_, G> {
         let mut diag =
             Diag::new(dcx, level, fluent::mir_build_non_exhaustive_patterns_type_not_empty);
-        diag.span(self.span);
+        diag.span(self.scrut_span);
         diag.code(E0004);
         let peeled_ty = self.ty.peel_refs();
         diag.arg("ty", self.ty);
@@ -502,26 +502,19 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo
             }
         }
 
-        let mut suggestion = None;
         let sm = self.cx.tcx.sess.source_map();
-        if self.span.eq_ctxt(self.expr_span) {
+        if let Some(braces_span) = self.braces_span {
             // Get the span for the empty match body `{}`.
-            let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.span) {
+            let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.scrut_span)
+            {
                 (format!("\n{snippet}"), "    ")
             } else {
                 (" ".to_string(), "")
             };
-            suggestion = Some((
-                self.span.shrink_to_hi().with_hi(self.expr_span.hi()),
-                format!(" {{{indentation}{more}_ => todo!(),{indentation}}}",),
-            ));
-        }
-
-        if let Some((span, sugg)) = suggestion {
             diag.span_suggestion_verbose(
-                span,
+                braces_span,
                 fluent::mir_build_suggestion,
-                sugg,
+                format!(" {{{indentation}{more}_ => todo!(),{indentation}}}"),
                 Applicability::HasPlaceholders,
             );
         } else {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 1e508ffc1e7..c697e16217b 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -716,10 +716,11 @@ impl<'tcx> Cx<'tcx> {
                 then: self.mirror_expr(then),
                 else_opt: else_opt.map(|el| self.mirror_expr(el)),
             },
-            hir::ExprKind::Match(discr, arms, _) => ExprKind::Match {
+            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,
             },
             hir::ExprKind::Loop(body, ..) => {
                 let block_ty = self.typeck_results().node_type(body.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 3a688a14dd5..a3e6c2abc51 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -144,16 +144,8 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
                 });
                 return;
             }
-            ExprKind::Match { scrutinee, scrutinee_hir_id, box ref arms } => {
-                let source = match ex.span.desugaring_kind() {
-                    Some(DesugaringKind::ForLoop) => hir::MatchSource::ForLoopDesugar,
-                    Some(DesugaringKind::QuestionMark) => {
-                        hir::MatchSource::TryDesugar(scrutinee_hir_id)
-                    }
-                    Some(DesugaringKind::Await) => hir::MatchSource::AwaitDesugar,
-                    _ => hir::MatchSource::Normal,
-                };
-                self.check_match(scrutinee, arms, source, ex.span);
+            ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => {
+                self.check_match(scrutinee, arms, match_source, ex.span);
             }
             ExprKind::Let { box ref pat, expr } => {
                 self.check_let(pat, Some(expr), ex.span);
@@ -505,8 +497,41 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                     None,
                 );
             } else {
+                // span after scrutinee, or after `.match`. That is, the braces, arms,
+                // and any whitespace preceding the braces.
+                let braces_span = match source {
+                    hir::MatchSource::Normal => scrut
+                        .span
+                        .find_ancestor_in_same_ctxt(expr_span)
+                        .map(|scrut_span| scrut_span.shrink_to_hi().with_hi(expr_span.hi())),
+                    hir::MatchSource::Postfix => {
+                        // This is horrendous, and we should deal with it by just
+                        // stashing the span of the braces somewhere (like in the match source).
+                        scrut.span.find_ancestor_in_same_ctxt(expr_span).and_then(|scrut_span| {
+                            let sm = self.tcx.sess.source_map();
+                            let brace_span = sm.span_extend_to_next_char(scrut_span, '{', true);
+                            if sm.span_to_snippet(sm.next_point(brace_span)).as_deref() == Ok("{") {
+                                let sp = brace_span.shrink_to_hi().with_hi(expr_span.hi());
+                                // We also need to extend backwards for whitespace
+                                sm.span_extend_prev_while(sp, |c| c.is_whitespace()).ok()
+                            } else {
+                                None
+                            }
+                        })
+                    }
+                    hir::MatchSource::ForLoopDesugar
+                    | hir::MatchSource::TryDesugar(_)
+                    | hir::MatchSource::AwaitDesugar
+                    | hir::MatchSource::FormatArgs => None,
+                };
                 self.error = Err(report_non_exhaustive_match(
-                    &cx, self.thir, scrut.ty, scrut.span, witnesses, arms, expr_span,
+                    &cx,
+                    self.thir,
+                    scrut.ty,
+                    scrut.span,
+                    witnesses,
+                    arms,
+                    braces_span,
                 ));
             }
         }
@@ -929,7 +954,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     sp: Span,
     witnesses: Vec<WitnessPat<'p, 'tcx>>,
     arms: &[ArmId],
-    expr_span: Span,
+    braces_span: Option<Span>,
 ) -> ErrorGuaranteed {
     let is_empty_match = arms.is_empty();
     let non_empty_enum = match scrut_ty.kind() {
@@ -941,8 +966,8 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     if is_empty_match && !non_empty_enum {
         return cx.tcx.dcx().emit_err(NonExhaustivePatternsTypeNotEmpty {
             cx,
-            expr_span,
-            span: sp,
+            scrut_span: sp,
+            braces_span,
             ty: scrut_ty,
         });
     }
@@ -1028,7 +1053,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     let mut suggestion = None;
     let sm = cx.tcx.sess.source_map();
     match arms {
-        [] if sp.eq_ctxt(expr_span) => {
+        [] if let Some(braces_span) = braces_span => {
             // Get the span for the empty match body `{}`.
             let (indentation, more) = if let Some(snippet) = sm.indentation_before(sp) {
                 (format!("\n{snippet}"), "    ")
@@ -1036,7 +1061,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
                 (" ".to_string(), "")
             };
             suggestion = Some((
-                sp.shrink_to_hi().with_hi(expr_span.hi()),
+                braces_span,
                 format!(" {{{indentation}{more}{suggested_arm},{indentation}}}",),
             ));
         }
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 256add3153c..d63db6ea8ed 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -420,14 +420,14 @@ where
     ) -> BasicBlock {
         // drop glue is sent straight to codegen
         // box cannot be directly dereferenced
-        let unique_ty = adt.non_enum_variant().fields[FieldIdx::new(0)].ty(self.tcx(), args);
+        let unique_ty = adt.non_enum_variant().fields[FieldIdx::ZERO].ty(self.tcx(), args);
         let unique_variant = unique_ty.ty_adt_def().unwrap().non_enum_variant();
-        let nonnull_ty = unique_variant.fields[FieldIdx::from_u32(0)].ty(self.tcx(), args);
+        let nonnull_ty = unique_variant.fields[FieldIdx::ZERO].ty(self.tcx(), args);
         let ptr_ty = Ty::new_imm_ptr(self.tcx(), args[0].expect_ty());
 
-        let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::new(0), unique_ty);
-        let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::new(0), nonnull_ty);
-        let ptr_place = self.tcx().mk_place_field(nonnull_place, FieldIdx::new(0), ptr_ty);
+        let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::ZERO, unique_ty);
+        let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::ZERO, nonnull_ty);
+        let ptr_place = self.tcx().mk_place_field(nonnull_place, FieldIdx::ZERO, ptr_ty);
         let interior = self.tcx().mk_place_deref(ptr_place);
 
         let interior_path = self.elaborator.deref_subpath(self.path);
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
index b8dbdf18db3..f9b79d72b05 100644
--- a/compiler/rustc_mir_transform/messages.ftl
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -1,6 +1,4 @@
 mir_transform_arithmetic_overflow = this arithmetic operation will overflow
-mir_transform_call_to_unsafe_label = call to unsafe function
-mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior
 mir_transform_const_defined_here = `const` item defined here
 
 mir_transform_const_modify = attempting to modify a `const` item
@@ -11,10 +9,6 @@ mir_transform_const_mut_borrow = taking a mutable reference to a `const` item
     .note2 = the mutable reference will refer to this temporary, not the original `const` item
     .note3 = mutable reference created due to call to this method
 
-mir_transform_const_ptr2int_label = cast of pointer to int
-mir_transform_const_ptr2int_note = casting pointers to integers in constants
-mir_transform_deref_ptr_label = dereference of raw pointer
-mir_transform_deref_ptr_note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 mir_transform_ffi_unwind_call = call to {$foreign ->
     [true] foreign function
     *[false] function pointer
@@ -23,56 +17,13 @@ mir_transform_ffi_unwind_call = call to {$foreign ->
 mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
     .suggestion = cast `{$ident}` to obtain a function pointer
 
-mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr
-mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
 mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
     .label = the value is held across this suspend point
     .note = {$reason}
     .help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
-
-mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability
-mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
-mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
-mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
 mir_transform_operation_will_panic = this operation will panic at runtime
 
-mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
-    [true] function or block
-    *[false] block
-    }
-    .not_inherited = items do not inherit unsafety from separate enclosing items
-
-mir_transform_target_feature_call_help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count ->
-    [1] feature
-    *[count] features
-    }: {$missing_target_features}
-
-mir_transform_target_feature_call_label = call to function with `#[target_feature]`
-mir_transform_target_feature_call_note = the {$build_target_features} target {$build_target_features_count ->
-    [1] feature
-    *[count] features
-    } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count ->
-    [1] it
-    *[count] them
-    } in `#[target_feature]`
-
 mir_transform_unaligned_packed_ref = reference to packed field is unaligned
     .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
     .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
     .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
-
-mir_transform_union_access_label = access to union field
-mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
-mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
-    .suggestion = consider wrapping the function body in an unsafe block
-    .note = an unsafe function restricts its caller, but its body is safe by default
-
-mir_transform_unused_unsafe = unnecessary `unsafe` block
-    .label = because it's nested under this `unsafe` block
-
-mir_transform_use_of_asm_label = use of inline assembly
-mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior
-mir_transform_use_of_extern_static_label = use of extern static
-mir_transform_use_of_extern_static_note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-mir_transform_use_of_static_mut_label = use of mutable static
-mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
deleted file mode 100644
index a0c3de3af58..00000000000
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ /dev/null
@@ -1,615 +0,0 @@
-use rustc_data_structures::unord::{ExtendUnord, UnordItems, UnordSet};
-use rustc_hir as hir;
-use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::hir_id::HirId;
-use rustc_hir::intravisit;
-use rustc_hir::{BlockCheckMode, ExprKind, Node};
-use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::*;
-use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
-use rustc_session::lint::Level;
-
-use std::ops::Bound;
-
-use crate::errors;
-
-pub struct UnsafetyChecker<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-    body_did: LocalDefId,
-    violations: Vec<UnsafetyViolation>,
-    source_info: SourceInfo,
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-
-    /// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
-    used_unsafe_blocks: UnordSet<HirId>,
-}
-
-impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
-    fn new(
-        body: &'a Body<'tcx>,
-        body_did: LocalDefId,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> Self {
-        Self {
-            body,
-            body_did,
-            violations: vec![],
-            source_info: SourceInfo::outermost(body.span),
-            tcx,
-            param_env,
-            used_unsafe_blocks: Default::default(),
-        }
-    }
-}
-
-impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        self.source_info = terminator.source_info;
-        match terminator.kind {
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::CoroutineDrop
-            | TerminatorKind::UnwindResume
-            | TerminatorKind::UnwindTerminate(_)
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. } => {
-                // safe (at least as emitted during MIR construction)
-            }
-
-            TerminatorKind::Call { ref func, .. } => {
-                let func_ty = func.ty(self.body, self.tcx);
-                let func_id =
-                    if let ty::FnDef(func_id, _) = func_ty.kind() { Some(func_id) } else { None };
-                let sig = func_ty.fn_sig(self.tcx);
-                if let hir::Unsafety::Unsafe = sig.unsafety() {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::CallToUnsafeFunction,
-                    )
-                }
-
-                if let Some(func_id) = func_id {
-                    self.check_target_features(*func_id);
-                }
-            }
-
-            TerminatorKind::InlineAsm { .. } => self.require_unsafe(
-                UnsafetyViolationKind::General,
-                UnsafetyViolationDetails::UseOfInlineAssembly,
-            ),
-        }
-        self.super_terminator(terminator, location);
-    }
-
-    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-        self.source_info = statement.source_info;
-        match statement.kind {
-            StatementKind::Assign(..)
-            | StatementKind::FakeRead(..)
-            | StatementKind::SetDiscriminant { .. }
-            | StatementKind::Deinit(..)
-            | StatementKind::StorageLive(..)
-            | StatementKind::StorageDead(..)
-            | StatementKind::Retag { .. }
-            | StatementKind::PlaceMention(..)
-            | StatementKind::Coverage(..)
-            | StatementKind::Intrinsic(..)
-            | StatementKind::ConstEvalCounter
-            | StatementKind::Nop => {
-                // safe (at least as emitted during MIR construction)
-            }
-            // `AscribeUserType` just exists to help MIR borrowck.
-            // It has no semantics, and everything is already reported by `PlaceMention`.
-            StatementKind::AscribeUserType(..) => return,
-        }
-        self.super_statement(statement, location);
-    }
-
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
-        match rvalue {
-            Rvalue::Aggregate(box ref aggregate, _) => match aggregate {
-                &AggregateKind::Array(..) | &AggregateKind::Tuple => {}
-                &AggregateKind::Adt(adt_did, ..) => {
-                    match self.tcx.layout_scalar_valid_range(adt_did) {
-                        (Bound::Unbounded, Bound::Unbounded) => {}
-                        _ => self.require_unsafe(
-                            UnsafetyViolationKind::General,
-                            UnsafetyViolationDetails::InitializingTypeWith,
-                        ),
-                    }
-                }
-                &AggregateKind::Closure(def_id, _)
-                | &AggregateKind::CoroutineClosure(def_id, _)
-                | &AggregateKind::Coroutine(def_id, _) => {
-                    let def_id = def_id.expect_local();
-                    let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
-                        self.tcx.mir_unsafety_check_result(def_id);
-                    self.register_violations(violations, used_unsafe_blocks.items().copied());
-                }
-            },
-            _ => {}
-        }
-        self.super_rvalue(rvalue, location);
-    }
-
-    fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
-        if let Operand::Constant(constant) = op {
-            let maybe_uneval = match constant.const_ {
-                Const::Val(..) | Const::Ty(_) => None,
-                Const::Unevaluated(uv, _) => Some(uv),
-            };
-
-            if let Some(uv) = maybe_uneval {
-                if uv.promoted.is_none() {
-                    let def_id = uv.def;
-                    if self.tcx.def_kind(def_id) == DefKind::InlineConst {
-                        let local_def_id = def_id.expect_local();
-                        let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
-                            self.tcx.mir_unsafety_check_result(local_def_id);
-                        self.register_violations(violations, used_unsafe_blocks.items().copied());
-                    }
-                }
-            }
-        }
-        self.super_operand(op, location);
-    }
-
-    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
-        // On types with `scalar_valid_range`, prevent
-        // * `&mut x.field`
-        // * `x.field = y;`
-        // * `&x.field` if `field`'s type has interior mutability
-        // because either of these would allow modifying the layout constrained field and
-        // insert values that violate the layout constraints.
-        if context.is_mutating_use() || context.is_borrow() {
-            self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use());
-        }
-
-        // Some checks below need the extra meta info of the local declaration.
-        let decl = &self.body.local_decls[place.local];
-
-        // Check the base local: it might be an unsafe-to-access static. We only check derefs of the
-        // temporary holding the static pointer to avoid duplicate errors
-        // <https://github.com/rust-lang/rust/pull/78068#issuecomment-731753506>.
-        if place.projection.first() == Some(&ProjectionElem::Deref) {
-            // If the projection root is an artificial local that we introduced when
-            // desugaring `static`, give a more specific error message
-            // (avoid the general "raw pointer" clause below, that would only be confusing).
-            if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
-                if self.tcx.is_mutable_static(def_id) {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::UseOfMutableStatic,
-                    );
-                    return;
-                } else if self.tcx.is_foreign_item(def_id) {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::UseOfExternStatic,
-                    );
-                    return;
-                }
-            }
-        }
-
-        // Check for raw pointer `Deref`.
-        for (base, proj) in place.iter_projections() {
-            if proj == ProjectionElem::Deref {
-                let base_ty = base.ty(self.body, self.tcx).ty;
-                if base_ty.is_unsafe_ptr() {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::DerefOfRawPointer,
-                    )
-                }
-            }
-        }
-
-        // Check for union fields. For this we traverse right-to-left, as the last `Deref` changes
-        // whether we *read* the union field or potentially *write* to it (if this place is being assigned to).
-        let mut saw_deref = false;
-        for (base, proj) in place.iter_projections().rev() {
-            if proj == ProjectionElem::Deref {
-                saw_deref = true;
-                continue;
-            }
-
-            let base_ty = base.ty(self.body, self.tcx).ty;
-            if base_ty.is_union() {
-                // If we did not hit a `Deref` yet and the overall place use is an assignment, the
-                // rules are different.
-                let assign_to_field = !saw_deref
-                    && matches!(
-                        context,
-                        PlaceContext::MutatingUse(
-                            MutatingUseContext::Store
-                                | MutatingUseContext::Drop
-                                | MutatingUseContext::AsmOutput
-                        )
-                    );
-                // If this is just an assignment, determine if the assigned type needs dropping.
-                if assign_to_field {
-                    // We have to check the actual type of the assignment, as that determines if the
-                    // old value is being dropped.
-                    let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty;
-                    if assigned_ty.needs_drop(self.tcx, self.param_env) {
-                        // This would be unsafe, but should be outright impossible since we reject
-                        // such unions.
-                        assert!(
-                            self.tcx.dcx().has_errors().is_some(),
-                            "union fields that need dropping should be impossible: {assigned_ty}"
-                        );
-                    }
-                } else {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::AccessToUnionField,
-                    )
-                }
-            }
-        }
-    }
-}
-
-impl<'tcx> UnsafetyChecker<'_, 'tcx> {
-    fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) {
-        // Violations can turn out to be `UnsafeFn` during analysis, but they should not start out as such.
-        assert_ne!(kind, UnsafetyViolationKind::UnsafeFn);
-
-        let source_info = self.source_info;
-        let lint_root = self.body.source_scopes[self.source_info.scope]
-            .local_data
-            .as_ref()
-            .assert_crate_local()
-            .lint_root;
-        self.register_violations(
-            [&UnsafetyViolation { source_info, lint_root, kind, details }],
-            UnordItems::empty(),
-        );
-    }
-
-    fn register_violations<'a>(
-        &mut self,
-        violations: impl IntoIterator<Item = &'a UnsafetyViolation>,
-        new_used_unsafe_blocks: UnordItems<HirId, impl Iterator<Item = HirId>>,
-    ) {
-        let safety = self.body.source_scopes[self.source_info.scope]
-            .local_data
-            .as_ref()
-            .assert_crate_local()
-            .safety;
-        match safety {
-            // `unsafe` blocks are required in safe code
-            Safety::Safe => violations.into_iter().for_each(|violation| {
-                match violation.kind {
-                    UnsafetyViolationKind::General => {}
-                    UnsafetyViolationKind::UnsafeFn => {
-                        bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context")
-                    }
-                }
-                if !self.violations.contains(violation) {
-                    self.violations.push(violation.clone())
-                }
-            }),
-            // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s
-            Safety::FnUnsafe => violations.into_iter().for_each(|violation| {
-                let mut violation = violation.clone();
-                violation.kind = UnsafetyViolationKind::UnsafeFn;
-                if !self.violations.contains(&violation) {
-                    self.violations.push(violation)
-                }
-            }),
-            Safety::BuiltinUnsafe => {}
-            Safety::ExplicitUnsafe(hir_id) => violations.into_iter().for_each(|_violation| {
-                self.used_unsafe_blocks.insert(hir_id);
-            }),
-        };
-
-        self.used_unsafe_blocks.extend_unord(new_used_unsafe_blocks);
-    }
-    fn check_mut_borrowing_layout_constrained_field(
-        &mut self,
-        place: Place<'tcx>,
-        is_mut_use: bool,
-    ) {
-        for (place_base, elem) in place.iter_projections().rev() {
-            match elem {
-                // Modifications behind a dereference don't affect the value of
-                // the pointer.
-                ProjectionElem::Deref => return,
-                ProjectionElem::Field(..) => {
-                    let ty = place_base.ty(&self.body.local_decls, self.tcx).ty;
-                    if let ty::Adt(def, _) = ty.kind() {
-                        if self.tcx.layout_scalar_valid_range(def.did())
-                            != (Bound::Unbounded, Bound::Unbounded)
-                        {
-                            let details = if is_mut_use {
-                                UnsafetyViolationDetails::MutationOfLayoutConstrainedField
-
-                            // Check `is_freeze` as late as possible to avoid cycle errors
-                            // with opaque types.
-                            } else if !place
-                                .ty(self.body, self.tcx)
-                                .ty
-                                .is_freeze(self.tcx, self.param_env)
-                            {
-                                UnsafetyViolationDetails::BorrowOfLayoutConstrainedField
-                            } else {
-                                continue;
-                            };
-                            self.require_unsafe(UnsafetyViolationKind::General, details);
-                        }
-                    }
-                }
-                _ => {}
-            }
-        }
-    }
-
-    /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether
-    /// the called function has target features the calling function hasn't.
-    fn check_target_features(&mut self, func_did: DefId) {
-        // Unsafety isn't required on wasm targets. For more information see
-        // the corresponding check in typeck/src/collect.rs
-        if self.tcx.sess.target.options.is_like_wasm {
-            return;
-        }
-
-        let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
-        // The body might be a constant, so it doesn't have codegen attributes.
-        let self_features = &self.tcx.body_codegen_attrs(self.body_did.to_def_id()).target_features;
-
-        // Is `callee_features` a subset of `calling_features`?
-        if !callee_features.iter().all(|feature| self_features.contains(feature)) {
-            let missing: Vec<_> = callee_features
-                .iter()
-                .copied()
-                .filter(|feature| !self_features.contains(feature))
-                .collect();
-            let build_enabled = self
-                .tcx
-                .sess
-                .target_features
-                .iter()
-                .copied()
-                .filter(|feature| missing.contains(feature))
-                .collect();
-            self.require_unsafe(
-                UnsafetyViolationKind::General,
-                UnsafetyViolationDetails::CallToFunctionWith { missing, build_enabled },
-            )
-        }
-    }
-}
-
-pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { mir_unsafety_check_result, ..*providers };
-}
-
-/// Context information for [`UnusedUnsafeVisitor`] traversal,
-/// saves (innermost) relevant context
-#[derive(Copy, Clone, Debug)]
-enum Context {
-    Safe,
-    /// in an `unsafe fn`
-    UnsafeFn,
-    /// in a *used* `unsafe` block
-    /// (i.e. a block without unused-unsafe warning)
-    UnsafeBlock(HirId),
-}
-
-struct UnusedUnsafeVisitor<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    used_unsafe_blocks: &'a UnordSet<HirId>,
-    context: Context,
-    unused_unsafes: &'a mut Vec<(HirId, UnusedUnsafe)>,
-}
-
-impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> {
-    fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
-        if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules {
-            let used = match self.tcx.lint_level_at_node(UNUSED_UNSAFE, block.hir_id) {
-                (Level::Allow, _) => true,
-                _ => self.used_unsafe_blocks.contains(&block.hir_id),
-            };
-            let unused_unsafe = match (self.context, used) {
-                (_, false) => UnusedUnsafe::Unused,
-                (Context::Safe, true) | (Context::UnsafeFn, true) => {
-                    let previous_context = self.context;
-                    self.context = Context::UnsafeBlock(block.hir_id);
-                    intravisit::walk_block(self, block);
-                    self.context = previous_context;
-                    return;
-                }
-                (Context::UnsafeBlock(hir_id), true) => UnusedUnsafe::InUnsafeBlock(hir_id),
-            };
-            self.unused_unsafes.push((block.hir_id, unused_unsafe));
-        }
-        intravisit::walk_block(self, block);
-    }
-
-    fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
-        self.visit_body(self.tcx.hir().body(c.body))
-    }
-
-    fn visit_fn(
-        &mut self,
-        fk: intravisit::FnKind<'tcx>,
-        _fd: &'tcx hir::FnDecl<'tcx>,
-        b: hir::BodyId,
-        _s: rustc_span::Span,
-        _id: LocalDefId,
-    ) {
-        if matches!(fk, intravisit::FnKind::Closure) {
-            self.visit_body(self.tcx.hir().body(b))
-        }
-    }
-}
-
-fn check_unused_unsafe(
-    tcx: TyCtxt<'_>,
-    def_id: LocalDefId,
-    used_unsafe_blocks: &UnordSet<HirId>,
-) -> Vec<(HirId, UnusedUnsafe)> {
-    let body_id = tcx.hir().maybe_body_owned_by(def_id);
-
-    let Some(body_id) = body_id else {
-        debug!("check_unused_unsafe({:?}) - no body found", def_id);
-        return vec![];
-    };
-
-    let body = tcx.hir().body(body_id);
-    let hir_id = tcx.local_def_id_to_hir_id(def_id);
-    let context = match tcx.hir().fn_sig_by_hir_id(hir_id) {
-        Some(sig) if sig.header.unsafety == hir::Unsafety::Unsafe => Context::UnsafeFn,
-        _ => Context::Safe,
-    };
-
-    debug!(
-        "check_unused_unsafe({:?}, context={:?}, body={:?}, used_unsafe_blocks={:?})",
-        def_id, body, context, used_unsafe_blocks
-    );
-
-    let mut unused_unsafes = vec![];
-
-    let mut visitor = UnusedUnsafeVisitor {
-        tcx,
-        used_unsafe_blocks,
-        context,
-        unused_unsafes: &mut unused_unsafes,
-    };
-    intravisit::Visitor::visit_body(&mut visitor, body);
-
-    unused_unsafes
-}
-
-fn mir_unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResult {
-    debug!("unsafety_violations({:?})", def);
-
-    // N.B., this borrow is valid because all the consumers of
-    // `mir_built` force this.
-    let body = &tcx.mir_built(def).borrow();
-
-    if body.is_custom_mir() || body.tainted_by_errors.is_some() {
-        return tcx.arena.alloc(UnsafetyCheckResult {
-            violations: Vec::new(),
-            used_unsafe_blocks: Default::default(),
-            unused_unsafes: Some(Vec::new()),
-        });
-    }
-
-    let param_env = tcx.param_env(def);
-
-    let mut checker = UnsafetyChecker::new(body, def, tcx, param_env);
-    checker.visit_body(body);
-
-    let unused_unsafes = (!tcx.is_typeck_child(def.to_def_id()))
-        .then(|| check_unused_unsafe(tcx, def, &checker.used_unsafe_blocks));
-
-    tcx.arena.alloc(UnsafetyCheckResult {
-        violations: checker.violations,
-        used_unsafe_blocks: checker.used_unsafe_blocks,
-        unused_unsafes,
-    })
-}
-
-fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
-    let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
-    let nested_parent = if let UnusedUnsafe::InUnsafeBlock(id) = kind {
-        Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
-    } else {
-        None
-    };
-    tcx.emit_node_span_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent });
-}
-
-pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    debug!("check_unsafety({:?})", def_id);
-
-    // closures and inline consts are handled by their parent fn.
-    if tcx.is_typeck_child(def_id.to_def_id()) {
-        return;
-    }
-
-    let UnsafetyCheckResult { violations, unused_unsafes, .. } =
-        tcx.mir_unsafety_check_result(def_id);
-    // Only suggest wrapping the entire function body in an unsafe block once
-    let mut suggest_unsafe_block = true;
-
-    for &UnsafetyViolation { source_info, lint_root, kind, ref details } in violations.iter() {
-        let details =
-            errors::RequiresUnsafeDetail { violation: details.clone(), span: source_info.span };
-
-        match kind {
-            UnsafetyViolationKind::General => {
-                let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, lint_root);
-                let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
-                    if let Node::Expr(block) = node
-                        && let ExprKind::Block(block, _) = block.kind
-                        && let BlockCheckMode::UnsafeBlock(_) = block.rules
-                    {
-                        true
-                    } else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id)
-                        && sig.header.is_unsafe()
-                    {
-                        true
-                    } else {
-                        false
-                    }
-                });
-                let enclosing = if let Some((id, _)) = note_non_inherited {
-                    Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
-                } else {
-                    None
-                };
-                tcx.dcx().emit_err(errors::RequiresUnsafe {
-                    span: source_info.span,
-                    enclosing,
-                    details,
-                    op_in_unsafe_fn_allowed,
-                });
-            }
-            UnsafetyViolationKind::UnsafeFn => {
-                tcx.emit_node_span_lint(
-                    UNSAFE_OP_IN_UNSAFE_FN,
-                    lint_root,
-                    source_info.span,
-                    errors::UnsafeOpInUnsafeFn {
-                        details,
-                        suggest_unsafe_block: suggest_unsafe_block.then(|| {
-                            let hir_id = tcx.local_def_id_to_hir_id(def_id);
-                            let fn_sig = tcx
-                                .hir()
-                                .fn_sig_by_hir_id(hir_id)
-                                .expect("this violation only occurs in fn");
-                            let body = tcx.hir().body_owned_by(def_id);
-                            let body_span = tcx.hir().body(body).value.span;
-                            let start = tcx.sess.source_map().start_point(body_span).shrink_to_hi();
-                            let end = tcx.sess.source_map().end_point(body_span).shrink_to_lo();
-                            (start, end, fn_sig.span)
-                        }),
-                    },
-                );
-                suggest_unsafe_block = false;
-            }
-        }
-    }
-
-    for &(block_id, kind) in unused_unsafes.as_ref().unwrap() {
-        report_unused_unsafe(tcx, kind, block_id);
-    }
-}
-
-fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool {
-    tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow
-}
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index f0a13f66555..e2a911f0dc7 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -168,7 +168,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
                 Place {
                     local: SELF_ARG,
                     projection: self.tcx().mk_place_elems(&[ProjectionElem::Field(
-                        FieldIdx::new(0),
+                        FieldIdx::ZERO,
                         self.ref_coroutine_ty,
                     )]),
                 },
@@ -267,7 +267,7 @@ impl<'tcx> TransformVisitor<'tcx> {
                 Rvalue::Aggregate(
                     Box::new(AggregateKind::Adt(
                         option_def_id,
-                        VariantIdx::from_usize(0),
+                        VariantIdx::ZERO,
                         self.tcx.mk_args(&[self.old_yield_ty.into()]),
                         None,
                         None,
@@ -329,7 +329,7 @@ impl<'tcx> TransformVisitor<'tcx> {
                     Rvalue::Aggregate(
                         Box::new(AggregateKind::Adt(
                             poll_def_id,
-                            VariantIdx::from_usize(0),
+                            VariantIdx::ZERO,
                             args,
                             None,
                             None,
@@ -358,7 +358,7 @@ impl<'tcx> TransformVisitor<'tcx> {
                     Rvalue::Aggregate(
                         Box::new(AggregateKind::Adt(
                             option_def_id,
-                            VariantIdx::from_usize(0),
+                            VariantIdx::ZERO,
                             args,
                             None,
                             None,
@@ -420,7 +420,7 @@ impl<'tcx> TransformVisitor<'tcx> {
                     Rvalue::Aggregate(
                         Box::new(AggregateKind::Adt(
                             coroutine_state_def_id,
-                            VariantIdx::from_usize(0),
+                            VariantIdx::ZERO,
                             args,
                             None,
                             None,
@@ -1226,7 +1226,7 @@ fn create_coroutine_drop_shim<'tcx>(
     tcx: TyCtxt<'tcx>,
     transform: &TransformVisitor<'tcx>,
     coroutine_ty: Ty<'tcx>,
-    body: &mut Body<'tcx>,
+    body: &Body<'tcx>,
     drop_clean: BasicBlock,
 ) -> Body<'tcx> {
     let mut body = body.clone();
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index e0bbd582d88..0866205dfd0 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -1,9 +1,68 @@
-//! A MIR pass which duplicates a coroutine's body and removes any derefs which
-//! would be present for upvars that are taken by-ref. The result of which will
-//! be a coroutine body that takes all of its upvars by-move, and which we stash
-//! into the `CoroutineInfo` for all coroutines returned by coroutine-closures.
+//! This pass constructs a second coroutine body sufficient for return from
+//! `FnOnce`/`AsyncFnOnce` implementations for coroutine-closures (e.g. async closures).
+//!
+//! Consider an async closure like:
+//! ```rust
+//! #![feature(async_closure)]
+//!
+//! let x = vec![1, 2, 3];
+//!
+//! let closure = async move || {
+//!     println!("{x:#?}");
+//! };
+//! ```
+//!
+//! This desugars to something like:
+//! ```rust,ignore (invalid-borrowck)
+//! let x = vec![1, 2, 3];
+//!
+//! let closure = move || {
+//!     async {
+//!         println!("{x:#?}");
+//!     }
+//! };
+//! ```
+//!
+//! Important to note here is that while the outer closure *moves* `x: Vec<i32>`
+//! into its upvars, the inner `async` coroutine simply captures a ref of `x`.
+//! This is the "magic" of async closures -- the futures that they return are
+//! allowed to borrow from their parent closure's upvars.
+//!
+//! However, what happens when we call `closure` with `AsyncFnOnce` (or `FnOnce`,
+//! since all async closures implement that too)? Well, recall the signature:
+//! ```
+//! use std::future::Future;
+//! pub trait AsyncFnOnce<Args>
+//! {
+//!     type CallOnceFuture: Future<Output = Self::Output>;
+//!     type Output;
+//!     fn async_call_once(
+//!         self,
+//!         args: Args
+//!     ) -> Self::CallOnceFuture;
+//! }
+//! ```
+//!
+//! This signature *consumes* the async closure (`self`) and returns a `CallOnceFuture`.
+//! How do we deal with the fact that the coroutine is supposed to take a reference
+//! to the captured `x` from the parent closure, when that parent closure has been
+//! destroyed?
+//!
+//! This is the second piece of magic of async closures. We can simply create a
+//! *second* `async` coroutine body where that `x` that was previously captured
+//! by reference is now captured by value. This means that we consume the outer
+//! closure and return a new coroutine that will hold onto all of these captures,
+//! and drop them when it is finished (i.e. after it has been `.await`ed).
+//!
+//! We do this with the analysis below, which detects the captures that come from
+//! borrowing from the outer closure, and we simply peel off a `deref` projection
+//! from them. This second body is stored alongside the first body, and optimized
+//! with it in lockstep. When we need to resolve a body for `FnOnce` or `AsyncFnOnce`,
+//! we use this "by move" body instead.
 
-use rustc_data_structures::fx::FxIndexSet;
+use itertools::Itertools;
+
+use rustc_data_structures::unord::UnordSet;
 use rustc_hir as hir;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{self, dump_mir, MirPass};
@@ -14,6 +73,8 @@ pub struct ByMoveBody;
 
 impl<'tcx> MirPass<'tcx> for ByMoveBody {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
+        // We only need to generate by-move coroutine bodies for coroutines that come
+        // from coroutine-closures.
         let Some(coroutine_def_id) = body.source.def_id().as_local() else {
             return;
         };
@@ -22,44 +83,70 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
         else {
             return;
         };
+
+        // Also, let's skip processing any bodies with errors, since there's no guarantee
+        // the MIR body will be constructed well.
         let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
         if coroutine_ty.references_error() {
             return;
         }
-        let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!("{body:#?}") };
 
-        let coroutine_kind = args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap();
+        let ty::Coroutine(_, coroutine_args) = *coroutine_ty.kind() else { bug!("{body:#?}") };
+        // We don't need to generate a by-move coroutine if the kind of the coroutine is
+        // already `FnOnce` -- that means that any upvars that the closure consumes have
+        // already been taken by-value.
+        let coroutine_kind = coroutine_args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap();
         if coroutine_kind == ty::ClosureKind::FnOnce {
             return;
         }
 
-        let mut by_ref_fields = FxIndexSet::default();
-        let by_move_upvars = Ty::new_tup_from_iter(
-            tcx,
-            tcx.closure_captures(coroutine_def_id).iter().enumerate().map(|(idx, capture)| {
-                if capture.is_by_ref() {
-                    by_ref_fields.insert(FieldIdx::from_usize(idx));
-                }
-                capture.place.ty()
-            }),
-        );
-        let by_move_coroutine_ty = Ty::new_coroutine(
-            tcx,
-            coroutine_def_id.to_def_id(),
-            ty::CoroutineArgs::new(
+        let parent_def_id = tcx.local_parent(coroutine_def_id);
+        let ty::CoroutineClosure(_, parent_args) =
+            *tcx.type_of(parent_def_id).instantiate_identity().kind()
+        else {
+            bug!();
+        };
+        let parent_closure_args = parent_args.as_coroutine_closure();
+        let num_args = parent_closure_args
+            .coroutine_closure_sig()
+            .skip_binder()
+            .tupled_inputs_ty
+            .tuple_fields()
+            .len();
+
+        let mut by_ref_fields = UnordSet::default();
+        for (idx, (coroutine_capture, parent_capture)) in tcx
+            .closure_captures(coroutine_def_id)
+            .iter()
+            // By construction we capture all the args first.
+            .skip(num_args)
+            .zip_eq(tcx.closure_captures(parent_def_id))
+            .enumerate()
+        {
+            // This upvar is captured by-move from the parent closure, but by-ref
+            // from the inner async block. That means that it's being borrowed from
+            // the outer closure body -- we need to change the coroutine to take the
+            // upvar by value.
+            if coroutine_capture.is_by_ref() && !parent_capture.is_by_ref() {
+                by_ref_fields.insert(FieldIdx::from_usize(num_args + idx));
+            }
+
+            // Make sure we're actually talking about the same capture.
+            // FIXME(async_closures): We could look at the `hir::Upvar` instead?
+            assert_eq!(coroutine_capture.place.ty(), parent_capture.place.ty());
+        }
+
+        let by_move_coroutine_ty = tcx
+            .instantiate_bound_regions_with_erased(parent_closure_args.coroutine_closure_sig())
+            .to_coroutine_given_kind_and_upvars(
                 tcx,
-                ty::CoroutineArgsParts {
-                    parent_args: args.as_coroutine().parent_args(),
-                    kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnOnce),
-                    resume_ty: args.as_coroutine().resume_ty(),
-                    yield_ty: args.as_coroutine().yield_ty(),
-                    return_ty: args.as_coroutine().return_ty(),
-                    witness: args.as_coroutine().witness(),
-                    tupled_upvars_ty: by_move_upvars,
-                },
-            )
-            .args,
-        );
+                parent_closure_args.parent_args(),
+                coroutine_def_id.to_def_id(),
+                ty::ClosureKind::FnOnce,
+                tcx.lifetimes.re_erased,
+                parent_closure_args.tupled_upvars_ty(),
+                parent_closure_args.coroutine_captures_by_ref_ty(),
+            );
 
         let mut by_move_body = body.clone();
         MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body);
@@ -73,7 +160,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
 
 struct MakeByMoveBody<'tcx> {
     tcx: TyCtxt<'tcx>,
-    by_ref_fields: FxIndexSet<FieldIdx>,
+    by_ref_fields: UnordSet<FieldIdx>,
     by_move_coroutine_ty: Ty<'tcx>,
 }
 
@@ -89,11 +176,11 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
         location: mir::Location,
     ) {
         if place.local == ty::CAPTURE_STRUCT_LOCAL
-            && !place.projection.is_empty()
-            && let mir::ProjectionElem::Field(idx, ty) = place.projection[0]
+            && let Some((&mir::ProjectionElem::Field(idx, ty), projection)) =
+                place.projection.split_first()
             && self.by_ref_fields.contains(&idx)
         {
-            let (begin, end) = place.projection[1..].split_first().unwrap();
+            let (begin, end) = projection.split_first().unwrap();
             // FIXME(async_closures): I'm actually a bit surprised to see that we always
             // initially deref the by-ref upvars. If this is not actually true, then we
             // will at least get an ICE that explains why this isn't true :^)
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index ae3b1a3d1af..d382d2c03c2 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -123,8 +123,11 @@ fn create_mappings<'tcx>(
     let body_span = hir_info.body_span;
 
     let source_file = source_map.lookup_source_file(body_span.lo());
-    use rustc_session::RemapFileNameExt;
-    let file_name = Symbol::intern(&source_file.name.for_codegen(tcx.sess).to_string_lossy());
+
+    use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
+    let file_name = Symbol::intern(
+        &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
+    );
 
     let term_for_bcb = |bcb| {
         coverage_counters
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index 96943435bab..318674f24e7 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -3,7 +3,6 @@
 //! Box is not actually a pointer so it is incorrect to dereference it directly.
 
 use rustc_hir::def_id::DefId;
-use rustc_index::Idx;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::*;
@@ -32,9 +31,9 @@ pub fn build_projection<'tcx>(
     ptr_ty: Ty<'tcx>,
 ) -> [PlaceElem<'tcx>; 3] {
     [
-        PlaceElem::Field(FieldIdx::new(0), unique_ty),
-        PlaceElem::Field(FieldIdx::new(0), nonnull_ty),
-        PlaceElem::Field(FieldIdx::new(0), ptr_ty),
+        PlaceElem::Field(FieldIdx::ZERO, unique_ty),
+        PlaceElem::Field(FieldIdx::ZERO, nonnull_ty),
+        PlaceElem::Field(FieldIdx::ZERO, ptr_ty),
     ]
 }
 
@@ -91,15 +90,14 @@ pub struct ElaborateBoxDerefs;
 impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if let Some(def_id) = tcx.lang_items().owned_box() {
-            let unique_did =
-                tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::from_u32(0)].did;
+            let unique_did = tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::ZERO].did;
 
             let Some(nonnull_def) = tcx.type_of(unique_did).instantiate_identity().ty_adt_def()
             else {
                 span_bug!(tcx.def_span(unique_did), "expected Box to contain Unique")
             };
 
-            let nonnull_did = nonnull_def.non_enum_variant().fields[FieldIdx::from_u32(0)].did;
+            let nonnull_did = nonnull_def.non_enum_variant().fields[FieldIdx::ZERO].did;
 
             let patch = MirPatch::new(body);
 
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 9297bc51fad..0634e321ea3 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -1,11 +1,6 @@
-use std::borrow::Cow;
-
-use rustc_errors::{
-    codes::*, Applicability, Diag, DiagArgValue, DiagCtxt, DiagMessage, Diagnostic,
-    EmissionGuarantee, Level, LintDiagnostic,
-};
+use rustc_errors::{codes::*, Diag, DiagMessage, LintDiagnostic};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
-use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
+use rustc_middle::mir::AssertKind;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::{self, Lint};
 use rustc_span::def_id::DefId;
@@ -42,168 +37,6 @@ pub(crate) struct UnalignedPackedRef {
     pub span: Span,
 }
 
-#[derive(LintDiagnostic)]
-#[diag(mir_transform_unused_unsafe)]
-pub(crate) struct UnusedUnsafe {
-    #[label(mir_transform_unused_unsafe)]
-    pub span: Span,
-    #[label]
-    pub nested_parent: Option<Span>,
-}
-
-pub(crate) struct RequiresUnsafe {
-    pub span: Span,
-    pub details: RequiresUnsafeDetail,
-    pub enclosing: Option<Span>,
-    pub op_in_unsafe_fn_allowed: bool,
-}
-
-// The primary message for this diagnostic should be '{$label} is unsafe and...',
-// so we need to eagerly translate the label here, which isn't supported by the derive API
-// We could also exhaustively list out the primary messages for all unsafe violations,
-// but this would result in a lot of duplication.
-impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for RequiresUnsafe {
-    #[track_caller]
-    fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
-        let mut diag = Diag::new(dcx, level, fluent::mir_transform_requires_unsafe);
-        diag.code(E0133);
-        diag.span(self.span);
-        diag.span_label(self.span, self.details.label());
-        let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter());
-        diag.arg("details", desc);
-        diag.arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed);
-        self.details.add_subdiagnostics(&mut diag);
-        if let Some(sp) = self.enclosing {
-            diag.span_label(sp, fluent::mir_transform_not_inherited);
-        }
-        diag
-    }
-}
-
-#[derive(Clone)]
-pub(crate) struct RequiresUnsafeDetail {
-    pub span: Span,
-    pub violation: UnsafetyViolationDetails,
-}
-
-impl RequiresUnsafeDetail {
-    // FIXME: make this translatable
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)]
-    fn add_subdiagnostics<G: EmissionGuarantee>(&self, diag: &mut Diag<'_, G>) {
-        use UnsafetyViolationDetails::*;
-        match self.violation {
-            CallToUnsafeFunction => {
-                diag.note(fluent::mir_transform_call_to_unsafe_note);
-            }
-            UseOfInlineAssembly => {
-                diag.note(fluent::mir_transform_use_of_asm_note);
-            }
-            InitializingTypeWith => {
-                diag.note(fluent::mir_transform_initializing_valid_range_note);
-            }
-            CastOfPointerToInt => {
-                diag.note(fluent::mir_transform_const_ptr2int_note);
-            }
-            UseOfMutableStatic => {
-                diag.note(fluent::mir_transform_use_of_static_mut_note);
-            }
-            UseOfExternStatic => {
-                diag.note(fluent::mir_transform_use_of_extern_static_note);
-            }
-            DerefOfRawPointer => {
-                diag.note(fluent::mir_transform_deref_ptr_note);
-            }
-            AccessToUnionField => {
-                diag.note(fluent::mir_transform_union_access_note);
-            }
-            MutationOfLayoutConstrainedField => {
-                diag.note(fluent::mir_transform_mutation_layout_constrained_note);
-            }
-            BorrowOfLayoutConstrainedField => {
-                diag.note(fluent::mir_transform_mutation_layout_constrained_borrow_note);
-            }
-            CallToFunctionWith { ref missing, ref build_enabled } => {
-                diag.help(fluent::mir_transform_target_feature_call_help);
-                diag.arg(
-                    "missing_target_features",
-                    DiagArgValue::StrListSepByAnd(
-                        missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
-                    ),
-                );
-                diag.arg("missing_target_features_count", missing.len());
-                if !build_enabled.is_empty() {
-                    diag.note(fluent::mir_transform_target_feature_call_note);
-                    diag.arg(
-                        "build_target_features",
-                        DiagArgValue::StrListSepByAnd(
-                            build_enabled
-                                .iter()
-                                .map(|feature| Cow::from(feature.to_string()))
-                                .collect(),
-                        ),
-                    );
-                    diag.arg("build_target_features_count", build_enabled.len());
-                }
-            }
-        }
-    }
-
-    fn label(&self) -> DiagMessage {
-        use UnsafetyViolationDetails::*;
-        match self.violation {
-            CallToUnsafeFunction => fluent::mir_transform_call_to_unsafe_label,
-            UseOfInlineAssembly => fluent::mir_transform_use_of_asm_label,
-            InitializingTypeWith => fluent::mir_transform_initializing_valid_range_label,
-            CastOfPointerToInt => fluent::mir_transform_const_ptr2int_label,
-            UseOfMutableStatic => fluent::mir_transform_use_of_static_mut_label,
-            UseOfExternStatic => fluent::mir_transform_use_of_extern_static_label,
-            DerefOfRawPointer => fluent::mir_transform_deref_ptr_label,
-            AccessToUnionField => fluent::mir_transform_union_access_label,
-            MutationOfLayoutConstrainedField => {
-                fluent::mir_transform_mutation_layout_constrained_label
-            }
-            BorrowOfLayoutConstrainedField => {
-                fluent::mir_transform_mutation_layout_constrained_borrow_label
-            }
-            CallToFunctionWith { .. } => fluent::mir_transform_target_feature_call_label,
-        }
-    }
-}
-
-pub(crate) struct UnsafeOpInUnsafeFn {
-    pub details: RequiresUnsafeDetail,
-
-    /// These spans point to:
-    ///  1. the start of the function body
-    ///  2. the end of the function body
-    ///  3. the function signature
-    pub suggest_unsafe_block: Option<(Span, Span, Span)>,
-}
-
-impl<'a> LintDiagnostic<'a, ()> for UnsafeOpInUnsafeFn {
-    #[track_caller]
-    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
-        let desc = diag.dcx.eagerly_translate_to_string(self.details.label(), [].into_iter());
-        diag.arg("details", desc);
-        diag.span_label(self.details.span, self.details.label());
-        self.details.add_subdiagnostics(diag);
-
-        if let Some((start, end, fn_sig)) = self.suggest_unsafe_block {
-            diag.span_note(fn_sig, fluent::mir_transform_note);
-            diag.tool_only_multipart_suggestion(
-                fluent::mir_transform_suggestion,
-                vec![(start, " unsafe {".into()), (end, "}".into())],
-                Applicability::MaybeIncorrect,
-            );
-        }
-    }
-
-    fn msg(&self) -> DiagMessage {
-        fluent::mir_transform_unsafe_op_in_unsafe_fn
-    }
-}
-
 pub(crate) struct AssertLint<P> {
     pub span: Span,
     pub assert_kind: AssertKind<P>,
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 59d6d89cf1f..d4f736d2a50 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -355,7 +355,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
     }
 
     fn insert_tuple(&mut self, values: Vec<VnIndex>) -> VnIndex {
-        self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::from_u32(0), values))
+        self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::ZERO, values))
     }
 
     #[instrument(level = "trace", skip(self), ret)]
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 5f74841151c..ab9fa165a20 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -324,7 +324,7 @@ impl<'tcx> Inliner<'tcx> {
             // do not need to catch this here, we can wait until the inliner decides to continue
             // inlining a second time.
             InstanceDef::VTableShim(_)
-            | InstanceDef::ReifyShim(_)
+            | InstanceDef::ReifyShim(..)
             | InstanceDef::FnPtrShim(..)
             | InstanceDef::ClosureOnceShim { .. }
             | InstanceDef::ConstructCoroutineInClosureShim { .. }
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index f2b6dcac586..7a1340f3a55 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -84,7 +84,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
                 // again, a function item can end up getting inlined. Thus we'll be able to cause
                 // a cycle that way
                 InstanceDef::VTableShim(_)
-                | InstanceDef::ReifyShim(_)
+                | InstanceDef::ReifyShim(..)
                 | InstanceDef::FnPtrShim(..)
                 | InstanceDef::ClosureOnceShim { .. }
                 | InstanceDef::ConstructCoroutineInClosureShim { .. }
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index a20958e74df..2218154ea5e 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -13,7 +13,7 @@ use rustc_const_eval::interpret::{
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::HirId;
-use rustc_index::{bit_set::BitSet, Idx, IndexVec};
+use rustc_index::{bit_set::BitSet, IndexVec};
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
@@ -124,10 +124,8 @@ impl<'tcx> Value<'tcx> {
                     fields.ensure_contains_elem(*idx, || Value::Uninit)
                 }
                 (PlaceElem::Field(..), val @ Value::Uninit) => {
-                    *val = Value::Aggregate {
-                        variant: VariantIdx::new(0),
-                        fields: Default::default(),
-                    };
+                    *val =
+                        Value::Aggregate { variant: VariantIdx::ZERO, fields: Default::default() };
                     val.project_mut(&[*proj])?
                 }
                 _ => return None,
@@ -572,7 +570,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     self.use_ecx(|this| this.ecx.overflowing_binary_op(bin_op, &left, &right))?;
                 let overflowed = ImmTy::from_bool(overflowed, self.tcx);
                 Value::Aggregate {
-                    variant: VariantIdx::new(0),
+                    variant: VariantIdx::ZERO,
                     fields: [Value::from(val), overflowed.into()].into_iter().collect(),
                 }
             }
@@ -607,7 +605,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                         | AggregateKind::Tuple
                         | AggregateKind::Closure(_, _)
                         | AggregateKind::Coroutine(_, _)
-                        | AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0),
+                        | AggregateKind::CoroutineClosure(_, _) => VariantIdx::ZERO,
                     },
                 }
             }
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 15988c0ea6b..e477c068229 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -53,7 +53,6 @@ mod add_moves_for_packed_drops;
 mod add_retag;
 mod check_const_item_mutation;
 mod check_packed_ref;
-pub mod check_unsafety;
 mod remove_place_mention;
 // This pass is public to allow external drivers to perform MIR cleanup
 mod add_subtyping_projections;
@@ -110,7 +109,7 @@ pub mod simplify;
 mod simplify_branches;
 mod simplify_comparison_integral;
 mod sroa;
-mod uninhabited_enum_branching;
+mod unreachable_enum_branching;
 mod unreachable_prop;
 
 use rustc_const_eval::transform::check_consts::{self, ConstCx};
@@ -120,7 +119,6 @@ use rustc_mir_dataflow::rustc_peek;
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 pub fn provide(providers: &mut Providers) {
-    check_unsafety::provide(providers);
     coverage::query::provide(providers);
     ffi_unwind_calls::provide(providers);
     shim::provide(providers);
@@ -280,11 +278,6 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
 }
 
 fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
-    // MIR unsafety check uses the raw mir, so make sure it is run.
-    if !tcx.sess.opts.unstable_opts.thir_unsafeck {
-        tcx.ensure_with_value().mir_unsafety_check_result(def);
-    }
-
     let mut body = tcx.build_mir(def);
 
     pass_manager::dump_mir_for_phase_change(tcx, &body);
@@ -580,9 +573,10 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             &remove_zsts::RemoveZsts,
             &remove_unneeded_drops::RemoveUnneededDrops,
             // Type instantiation may create uninhabited enums.
-            &uninhabited_enum_branching::UninhabitedEnumBranching,
+            // Also eliminates some unreachable branches based on variants of enums.
+            &unreachable_enum_branching::UnreachableEnumBranching,
             &unreachable_prop::UnreachablePropagation,
-            &o1(simplify::SimplifyCfg::AfterUninhabitedEnumBranching),
+            &o1(simplify::SimplifyCfg::AfterUnreachableEnumBranching),
             // Inlining may have introduced a lot of redundant code and a large move pattern.
             // Now, we need to shrink the generated MIR.
 
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 7d4c1b9c21a..7e8920604c1 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -90,6 +90,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                     sym::wrapping_add
                     | sym::wrapping_sub
                     | sym::wrapping_mul
+                    | sym::three_way_compare
                     | sym::unchecked_add
                     | sym::unchecked_sub
                     | sym::unchecked_mul
@@ -109,6 +110,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                             sym::wrapping_add => BinOp::Add,
                             sym::wrapping_sub => BinOp::Sub,
                             sym::wrapping_mul => BinOp::Mul,
+                            sym::three_way_compare => BinOp::Cmp,
                             sym::unchecked_add => BinOp::AddUnchecked,
                             sym::unchecked_sub => BinOp::SubUnchecked,
                             sym::unchecked_mul => BinOp::MulUnchecked,
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index c3a92911bbf..232c290e0fb 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -84,7 +84,7 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
 ///
 /// If the MIR fulfills both these conditions, this function returns the `Local` that is assigned
 /// to the return place along all possible paths through the control-flow graph.
-fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option<Local> {
+fn local_eligible_for_nrvo(body: &mir::Body<'_>) -> Option<Local> {
     if IsReturnPlaceRead::run(body) {
         return None;
     }
@@ -118,10 +118,7 @@ fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option<Local> {
     copied_to_return_place
 }
 
-fn find_local_assigned_to_return_place(
-    start: BasicBlock,
-    body: &mut mir::Body<'_>,
-) -> Option<Local> {
+fn find_local_assigned_to_return_place(start: BasicBlock, body: &mir::Body<'_>) -> Option<Local> {
     let mut block = start;
     let mut seen = BitSet::new_empty(body.basic_blocks.len());
 
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 2951897ebd6..a9d4b860b7a 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -434,7 +434,7 @@ impl<'tcx> Validator<'_, 'tcx> {
             Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
 
             // ptr-to-int casts are not possible in consts and thus not promotable
-            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable),
+            Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => return Err(Unpromotable),
 
             // all other casts including int-to-ptr casts are fine, they just use the integer value
             // at pointer type.
@@ -525,6 +525,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                     | BinOp::Lt
                     | BinOp::Ge
                     | BinOp::Gt
+                    | BinOp::Cmp
                     | BinOp::Offset
                     | BinOp::Add
                     | BinOp::AddUnchecked
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index b60ee7649b2..fa6906bdd55 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -55,7 +55,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
         // a virtual call, or a direct call to a function for which
         // indirect calls must be codegen'd differently than direct ones
         // (such as `#[track_caller]`).
-        ty::InstanceDef::ReifyShim(def_id) => {
+        ty::InstanceDef::ReifyShim(def_id, _) => {
             build_call_shim(tcx, instance, None, CallKind::Direct(def_id))
         }
         ty::InstanceDef::ClosureOnceShim { call_once: _, track_caller: _ } => {
@@ -985,7 +985,7 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t
     let locals = local_decls_for_sig(&sig, span);
 
     let source_info = SourceInfo::outermost(span);
-    // FIXME: use `expose_addr` once we figure out whether function pointers have meaningful provenance.
+    // FIXME: use `expose_provenance` once we figure out whether function pointers have meaningful provenance.
     let rvalue = Rvalue::Cast(
         CastKind::FnPtrToPtr,
         Operand::Move(Place::from(Local::new(1))),
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 574330cc355..5bbe3bb747f 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -44,7 +44,7 @@ pub enum SimplifyCfg {
     PreOptimizations,
     Final,
     MakeShim,
-    AfterUninhabitedEnumBranching,
+    AfterUnreachableEnumBranching,
 }
 
 impl SimplifyCfg {
@@ -57,8 +57,8 @@ impl SimplifyCfg {
             SimplifyCfg::PreOptimizations => "SimplifyCfg-pre-optimizations",
             SimplifyCfg::Final => "SimplifyCfg-final",
             SimplifyCfg::MakeShim => "SimplifyCfg-make_shim",
-            SimplifyCfg::AfterUninhabitedEnumBranching => {
-                "SimplifyCfg-after-uninhabited-enum-branching"
+            SimplifyCfg::AfterUnreachableEnumBranching => {
+                "SimplifyCfg-after-unreachable-enum-branching"
             }
         }
     }
@@ -415,7 +415,7 @@ fn make_local_map<V>(
     used_locals: &UsedLocals,
 ) -> IndexVec<Local, Option<Local>> {
     let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, local_decls);
-    let mut used = Local::new(0);
+    let mut used = Local::ZERO;
 
     for alive_index in local_decls.indices() {
         // `is_used` treats the `RETURN_PLACE` and arguments as used.
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
index 57fe46ad75a..66b6235eb93 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
@@ -1,4 +1,4 @@
-//! A pass that eliminates branches on uninhabited enum variants.
+//! A pass that eliminates branches on uninhabited or unreachable enum variants.
 
 use crate::MirPass;
 use rustc_data_structures::fx::FxHashSet;
@@ -11,7 +11,7 @@ use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_target::abi::{Abi, Variants};
 
-pub struct UninhabitedEnumBranching;
+pub struct UnreachableEnumBranching;
 
 fn get_discriminant_local(terminator: &TerminatorKind<'_>) -> Option<Local> {
     if let TerminatorKind::SwitchInt { discr: Operand::Move(p), .. } = terminator {
@@ -71,13 +71,13 @@ fn variant_discriminants<'tcx>(
     }
 }
 
-impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
+impl<'tcx> MirPass<'tcx> for UnreachableEnumBranching {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        trace!("UninhabitedEnumBranching starting for {:?}", body.source);
+        trace!("UnreachableEnumBranching starting for {:?}", body.source);
 
         let mut unreachable_targets = Vec::new();
         let mut patch = MirPatch::new(body);
@@ -96,8 +96,10 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
             );
 
             let mut allowed_variants = if let Ok(layout) = layout {
+                // Find allowed variants based on uninhabited.
                 variant_discriminants(&layout, discriminant_ty, tcx)
             } else if let Some(variant_range) = discriminant_ty.variant_range(tcx) {
+                // If there are some generics, we can still get the allowed variants.
                 variant_range
                     .map(|variant| {
                         discriminant_ty.discriminant_for_variant(tcx, variant).unwrap().val
@@ -121,9 +123,26 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
             }
             let otherwise_is_empty_unreachable =
                 body.basic_blocks[targets.otherwise()].is_empty_unreachable();
-            // After resolving https://github.com/llvm/llvm-project/issues/78578,
-            // we can remove the limit on the number of successors.
             fn check_successors(basic_blocks: &BasicBlocks<'_>, bb: BasicBlock) -> bool {
+                // After resolving https://github.com/llvm/llvm-project/issues/78578,
+                // We can remove this check.
+                // The main issue here is that `early-tailduplication` causes compile time overhead
+                // and potential performance problems.
+                // Simply put, when encounter a switch (indirect branch) statement,
+                // `early-tailduplication` tries to duplicate the switch branch statement with BB
+                // into (each) predecessors. This makes CFG very complex.
+                // We can understand it as it transforms the following code
+                // ```rust
+                // match a { ... many cases };
+                // match b { ... many cases };
+                // ```
+                // into
+                // ```rust
+                // match a { ... many match b { goto BB cases } }
+                // ... BB cases
+                // ```
+                // Abandon this transformation when it is possible (the best effort)
+                // to encounter the problem.
                 let mut successors = basic_blocks[bb].terminator().successors();
                 let Some(first_successor) = successors.next() else { return true };
                 if successors.next().is_some() {
@@ -136,11 +155,32 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
                 };
                 true
             }
+            // If and only if there is a variant that does not have a branch set,
+            // change the current of otherwise as the variant branch and set otherwise to unreachable.
+            // It transforms following code
+            // ```rust
+            // match c {
+            //     Ordering::Less => 1,
+            //     Ordering::Equal => 2,
+            //     _ => 3,
+            // }
+            // ```
+            // to
+            // ```rust
+            // match c {
+            //     Ordering::Less => 1,
+            //     Ordering::Equal => 2,
+            //     Ordering::Greater => 3,
+            // }
+            // ```
             let otherwise_is_last_variant = !otherwise_is_empty_unreachable
                 && allowed_variants.len() == 1
-                && check_successors(&body.basic_blocks, targets.otherwise());
+                // Despite the LLVM issue, we hope that small enum can still be transformed.
+                // This is valuable for both `a <= b` and `if let Some/Ok(v)`.
+                && (targets.all_targets().len() <= 3
+                    || check_successors(&body.basic_blocks, targets.otherwise()));
             let replace_otherwise_to_unreachable = otherwise_is_last_variant
-                || !otherwise_is_empty_unreachable && allowed_variants.is_empty();
+                || (!otherwise_is_empty_unreachable && allowed_variants.is_empty());
 
             if unreachable_targets.is_empty() && !replace_otherwise_to_unreachable {
                 continue;
@@ -150,6 +190,7 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
             let mut targets = targets.clone();
             if replace_otherwise_to_unreachable {
                 if otherwise_is_last_variant {
+                    // We have checked that `allowed_variants` has only one element.
                     #[allow(rustc::potential_query_instability)]
                     let last_variant = *allowed_variants.iter().next().unwrap();
                     targets.add_target(last_variant, targets.otherwise());
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 9c4a6e69a3c..2a91d69529a 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -14,6 +14,7 @@ use rustc_middle::ty::adjustment::CustomCoerceUnsized;
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{self, Ty};
+use rustc_span::def_id::DefId;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::ErrorGuaranteed;
 
@@ -57,13 +58,24 @@ fn custom_coerce_unsize_info<'tcx>(
 /// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
 /// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
 /// unlinkable calls.
+///
+/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
 pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
 ) -> bool {
-    !instance.def_id().is_local()
+    fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+        if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name {
+            name.as_str().starts_with("llvm.")
+        } else {
+            false
+        }
+    }
+
+    let def_id = instance.def_id();
+    !def_id.is_local()
         && tcx.is_compiler_builtins(LOCAL_CRATE)
-        && tcx.codegen_fn_attrs(instance.def_id()).link_name.is_none()
+        && !is_llvm_intrinsic(tcx, def_id)
         && !should_codegen_locally(tcx, instance)
 }
 
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 16d8453ea24..1899517c0e2 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -296,10 +296,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
         Region::new_anon_bound(self.interner(), self.binder_index, var)
     }
 
-    fn fold_ty(&mut self, t: I::Ty) -> I::Ty
-    where
-        I::Ty: TypeSuperFoldable<I>,
-    {
+    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
         let kind = match t.kind() {
             ty::Infer(i) => match i {
                 ty::TyVar(vid) => {
@@ -378,47 +375,48 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
         Ty::new_anon_bound(self.interner(), self.binder_index, var)
     }
 
-    fn fold_const(&mut self, c: I::Const) -> I::Const
-    where
-        I::Const: TypeSuperFoldable<I>,
-    {
+    fn fold_const(&mut self, c: I::Const) -> I::Const {
+        // We could canonicalize all consts with static types, but the only ones we
+        // *really* need to worry about are the ones that we end up putting into `CanonicalVarKind`
+        // since canonical vars can't reference other canonical vars.
+        let ty = c
+            .ty()
+            .fold_with(&mut RegionsToStatic { interner: self.interner(), binder: ty::INNERMOST });
         let kind = match c.kind() {
-            ty::ConstKind::Infer(i) => {
-                // FIXME: we should fold the ty too eventually
-                match i {
-                    ty::InferConst::Var(vid) => {
-                        assert_eq!(
-                            self.infcx.root_ct_var(vid),
-                            vid,
-                            "region vid should have been resolved fully before canonicalization"
-                        );
-                        assert_eq!(
-                            self.infcx.probe_ct_var(vid),
-                            None,
-                            "region vid should have been resolved fully before canonicalization"
-                        );
-                        CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), c.ty())
-                    }
-                    ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect,
-                    ty::InferConst::Fresh(_) => todo!(),
+            ty::ConstKind::Infer(i) => match i {
+                ty::InferConst::Var(vid) => {
+                    assert_eq!(
+                        self.infcx.root_ct_var(vid),
+                        vid,
+                        "region vid should have been resolved fully before canonicalization"
+                    );
+                    assert_eq!(
+                        self.infcx.probe_ct_var(vid),
+                        None,
+                        "region vid should have been resolved fully before canonicalization"
+                    );
+                    CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), ty)
                 }
-            }
+                ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect,
+                ty::InferConst::Fresh(_) => todo!(),
+            },
             ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
                 CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
                     PlaceholderLike::new(placeholder.universe(), self.variables.len().into()),
-                    c.ty(),
+                    ty,
                 ),
                 CanonicalizeMode::Response { .. } => {
-                    CanonicalVarKind::PlaceholderConst(placeholder, c.ty())
+                    CanonicalVarKind::PlaceholderConst(placeholder, ty)
                 }
             },
             ty::ConstKind::Param(_) => match self.canonicalize_mode {
                 CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
                     PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()),
-                    c.ty(),
+                    ty,
                 ),
                 CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"),
             },
+            // FIXME: See comment above -- we could fold the region separately or something.
             ty::ConstKind::Bound(_, _)
             | ty::ConstKind::Unevaluated(_)
             | ty::ConstKind::Value(_)
@@ -435,6 +433,35 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
             }),
         );
 
-        Const::new_anon_bound(self.interner(), self.binder_index, var, c.ty())
+        Const::new_anon_bound(self.interner(), self.binder_index, var, ty)
+    }
+}
+
+struct RegionsToStatic<I> {
+    interner: I,
+    binder: ty::DebruijnIndex,
+}
+
+impl<I: Interner> TypeFolder<I> for RegionsToStatic<I> {
+    fn interner(&self) -> I {
+        self.interner
+    }
+
+    fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
+    where
+        T: TypeFoldable<I>,
+        I::Binder<T>: TypeSuperFoldable<I>,
+    {
+        self.binder.shift_in(1);
+        let t = t.fold_with(self);
+        self.binder.shift_out(1);
+        t
+    }
+
+    fn fold_region(&mut self, r: I::Region) -> I::Region {
+        match r.kind() {
+            ty::ReBound(db, _) if self.binder > db => r,
+            _ => Region::new_static(self.interner()),
+        }
     }
 }
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 63b2b47630b..69b48bf0aff 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -30,7 +30,7 @@ use unescape_error_reporting::{emit_unescape_error, escaped_char};
 //
 // This assertion is in this crate, rather than in `rustc_lexer`, because that
 // crate cannot depend on `rustc_data_structures`.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12);
 
 #[derive(Clone, Debug)]
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index a1dd7d6f673..baaed5ec37b 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -454,7 +454,7 @@ fn make_token_stream(
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 18fb858c84c..012285e4644 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -860,6 +860,7 @@ impl<'a> Parser<'a> {
                     ExprKind::MethodCall(_) => "a method call",
                     ExprKind::Call(_, _) => "a function call",
                     ExprKind::Await(_, _) => "`.await`",
+                    ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
                     ExprKind::Err(_) => return Ok(with_postfix),
                     _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
                 }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 1971591364d..09bc00403f3 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -179,7 +179,7 @@ pub struct Parser<'a> {
 
 // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
 // it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Parser<'_>, 264);
 
 /// Stores span information about a closure.
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 2bb4b09e337..ccda43c827c 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -1087,7 +1087,7 @@ fn unescape_string(string: &str) -> Option<string::String> {
 }
 
 // Assert a reasonable size for `Piece`
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_index::static_assert_size!(Piece<'_>, 16);
 
 #[cfg(test)]
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index f34e8d96f05..438c583db49 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -7,6 +7,7 @@ use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{sigpipe, CrateType, EntryFnType};
+use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
 
@@ -165,10 +166,14 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
 
     // There is no main function.
     let mut has_filename = true;
-    let filename = tcx.sess.local_crate_source_file().unwrap_or_else(|| {
-        has_filename = false;
-        Default::default()
-    });
+    let filename = tcx
+        .sess
+        .local_crate_source_file()
+        .map(|src| src.for_scope(&tcx.sess, RemapPathScopeComponents::DIAGNOSTICS).to_path_buf())
+        .unwrap_or_else(|| {
+            has_filename = false;
+            Default::default()
+        });
     let main_def_opt = tcx.resolutions(()).main_def;
     let code = E0601;
     let add_teach_note = tcx.sess.teach(code);
diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml
index 6357d18b9da..0cb47e03441 100644
--- a/compiler/rustc_pattern_analysis/Cargo.toml
+++ b/compiler/rustc_pattern_analysis/Cargo.toml
@@ -24,7 +24,7 @@ tracing = "0.1"
 
 [dev-dependencies]
 tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "ansi"] }
-tracing-tree = "0.2.0"
+tracing-tree = "0.3.0"
 
 [features]
 default = ["rustc"]
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index 95c5556410d..44f09b66bf6 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -140,6 +140,34 @@
 //! [`ConstructorSet::split`]. The invariants of [`SplitConstructorSet`] are also of interest.
 //!
 //!
+//! ## Unions
+//!
+//! Unions allow us to match a value via several overlapping representations at the same time. For
+//! example, the following is exhaustive because when seeing the value as a boolean we handled all
+//! possible cases (other cases such as `n == 3` would trigger UB).
+//!
+//! ```rust
+//! # fn main() {
+//! union U8AsBool {
+//!     n: u8,
+//!     b: bool,
+//! }
+//! let x = U8AsBool { n: 1 };
+//! unsafe {
+//!     match x {
+//!         U8AsBool { n: 2 } => {}
+//!         U8AsBool { b: true } => {}
+//!         U8AsBool { b: false } => {}
+//!     }
+//! }
+//! # }
+//! ```
+//!
+//! Pattern-matching has no knowledge that e.g. `false as u8 == 0`, so the values we consider in the
+//! algorithm look like `U8AsBool { b: true, n: 2 }`. In other words, for the most part a union is
+//! treated like a struct with the same fields. The difference lies in how we construct witnesses of
+//! non-exhaustiveness.
+//!
 //!
 //! ## Opaque patterns
 //!
@@ -155,13 +183,13 @@ use std::iter::once;
 use smallvec::SmallVec;
 
 use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
-use rustc_index::bit_set::GrowableBitSet;
+use rustc_index::bit_set::{BitSet, GrowableBitSet};
+use rustc_index::IndexVec;
 
 use self::Constructor::*;
 use self::MaybeInfiniteInt::*;
 use self::SliceKind::*;
 
-use crate::index;
 use crate::PatCx;
 
 /// Whether we have seen a constructor in the column or not.
@@ -920,10 +948,7 @@ pub enum ConstructorSet<Cx: PatCx> {
     Struct { empty: bool },
     /// This type has the following list of constructors. If `variants` is empty and
     /// `non_exhaustive` is false, don't use this; use `NoConstructors` instead.
-    Variants {
-        variants: index::IdxContainer<Cx::VariantIdx, VariantVisibility>,
-        non_exhaustive: bool,
-    },
+    Variants { variants: IndexVec<Cx::VariantIdx, VariantVisibility>, non_exhaustive: bool },
     /// The type is `&T`.
     Ref,
     /// The type is a union.
@@ -977,7 +1002,6 @@ impl<Cx: PatCx> ConstructorSet<Cx> {
     /// any) are missing; 2/ split constructors to handle non-trivial intersections e.g. on ranges
     /// or slices. This can get subtle; see [`SplitConstructorSet`] for details of this operation
     /// and its invariants.
-    #[instrument(level = "debug", skip(self, ctors), ret)]
     pub fn split<'a>(
         &self,
         ctors: impl Iterator<Item = &'a Constructor<Cx>> + Clone,
@@ -1025,7 +1049,7 @@ impl<Cx: PatCx> ConstructorSet<Cx> {
                 }
             }
             ConstructorSet::Variants { variants, non_exhaustive } => {
-                let mut seen_set = index::IdxSet::new_empty(variants.len());
+                let mut seen_set = BitSet::new_empty(variants.len());
                 for idx in seen.iter().filter_map(|c| c.as_variant()) {
                     seen_set.insert(idx);
                 }
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 1a1da5c55f6..6e8843d9049 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -25,50 +25,9 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 use std::fmt;
 
-#[cfg(feature = "rustc")]
-pub mod index {
-    // Faster version when the indices of variants are `0..variants.len()`.
-    pub use rustc_index::bit_set::BitSet as IdxSet;
-    pub use rustc_index::Idx;
-    pub use rustc_index::IndexVec as IdxContainer;
-}
-#[cfg(not(feature = "rustc"))]
-pub mod index {
-    // Slower version when the indices of variants are something else.
-    pub trait Idx: Copy + PartialEq + Eq + std::hash::Hash {}
-    impl<T: Copy + PartialEq + Eq + std::hash::Hash> Idx for T {}
-
-    #[derive(Debug)]
-    pub struct IdxContainer<K, V>(pub rustc_hash::FxHashMap<K, V>);
-    impl<K: Idx, V> IdxContainer<K, V> {
-        pub fn len(&self) -> usize {
-            self.0.len()
-        }
-        pub fn iter_enumerated(&self) -> impl Iterator<Item = (K, &V)> {
-            self.0.iter().map(|(k, v)| (*k, v))
-        }
-    }
-
-    impl<V> FromIterator<V> for IdxContainer<usize, V> {
-        fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
-            Self(iter.into_iter().enumerate().collect())
-        }
-    }
-
-    #[derive(Debug)]
-    pub struct IdxSet<T>(pub rustc_hash::FxHashSet<T>);
-    impl<T: Idx> IdxSet<T> {
-        pub fn new_empty(_len: usize) -> Self {
-            Self(Default::default())
-        }
-        pub fn contains(&self, elem: T) -> bool {
-            self.0.contains(&elem)
-        }
-        pub fn insert(&mut self, elem: T) {
-            self.0.insert(elem);
-        }
-    }
-}
+// Re-exports to avoid rustc_index version issues.
+pub use rustc_index::Idx;
+pub use rustc_index::IndexVec;
 
 #[cfg(feature = "rustc")]
 use rustc_middle::ty::Ty;
@@ -96,7 +55,7 @@ pub trait PatCx: Sized + fmt::Debug {
     /// Errors that can abort analysis.
     type Error: fmt::Debug;
     /// The index of an enum variant.
-    type VariantIdx: Clone + index::Idx + fmt::Debug;
+    type VariantIdx: Clone + Idx + fmt::Debug;
     /// A string literal
     type StrLit: Clone + PartialEq + fmt::Debug;
     /// Extra data to store in a match arm.
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index b0f506c3651..467f09e4c29 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -186,7 +186,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
 
     /// Returns the types of the fields for a given constructor. The result must have a length of
     /// `ctor.arity()`.
-    #[instrument(level = "trace", skip(self))]
     pub(crate) fn ctor_sub_tys<'a>(
         &'a self,
         ctor: &'a Constructor<'p, 'tcx>,
@@ -283,7 +282,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
     /// Creates a set that represents all the constructors of `ty`.
     ///
     /// See [`crate::constructor`] for considerations of emptiness.
-    #[instrument(level = "debug", skip(self), ret)]
     pub fn ctors_for_ty(
         &self,
         ty: RevealedTy<'tcx>,
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index cdc03eaeb37..7246039174a 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -871,12 +871,14 @@ impl<Cx: PatCx> PlaceInfo<Cx> {
     where
         Cx: 'a,
     {
+        debug!(?self.ty);
         if self.private_uninhabited {
             // Skip the whole column
             return Ok((smallvec![Constructor::PrivateUninhabited], vec![]));
         }
 
         let ctors_for_ty = cx.ctors_for_ty(&self.ty)?;
+        debug!(?ctors_for_ty);
 
         // We treat match scrutinees of type `!` or `EmptyEnum` differently.
         let is_toplevel_exception =
@@ -895,6 +897,7 @@ impl<Cx: PatCx> PlaceInfo<Cx> {
 
         // Analyze the constructors present in this column.
         let mut split_set = ctors_for_ty.split(ctors);
+        debug!(?split_set);
         let all_missing = split_set.present.is_empty();
 
         // Build the set of constructors we will specialize with. It must cover the whole type, so
@@ -1254,7 +1257,7 @@ impl<'p, Cx: PatCx> Matrix<'p, Cx> {
 /// + true  + [Second(true)]    +
 /// + false + [_]               +
 /// + _     + [_, _, tail @ ..] +
-/// | ✓     | ?                 | // column validity
+/// | ✓     | ?                 | // validity
 /// ```
 impl<'p, Cx: PatCx> fmt::Debug for Matrix<'p, Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1285,7 +1288,7 @@ impl<'p, Cx: PatCx> fmt::Debug for Matrix<'p, Cx> {
                 write!(f, " {sep}")?;
             }
             if is_validity_row {
-                write!(f, " // column validity")?;
+                write!(f, " // validity")?;
             }
             write!(f, "\n")?;
         }
@@ -1381,12 +1384,35 @@ impl<Cx: PatCx> WitnessStack<Cx> {
     /// pats: [(false, "foo"), _, true]
     /// result: [Enum::Variant { a: (false, "foo"), b: _ }, true]
     /// ```
-    fn apply_constructor(&mut self, pcx: &PlaceCtxt<'_, Cx>, ctor: &Constructor<Cx>) {
+    fn apply_constructor(
+        mut self,
+        pcx: &PlaceCtxt<'_, Cx>,
+        ctor: &Constructor<Cx>,
+    ) -> SmallVec<[Self; 1]> {
         let len = self.0.len();
         let arity = pcx.ctor_arity(ctor);
-        let fields = self.0.drain((len - arity)..).rev().collect();
-        let pat = WitnessPat::new(ctor.clone(), fields, pcx.ty.clone());
-        self.0.push(pat);
+        let fields: Vec<_> = self.0.drain((len - arity)..).rev().collect();
+        if matches!(ctor, Constructor::UnionField)
+            && fields.iter().filter(|p| !matches!(p.ctor(), Constructor::Wildcard)).count() >= 2
+        {
+            // Convert a `Union { a: p, b: q }` witness into `Union { a: p }` and `Union { b: q }`.
+            // First add `Union { .. }` to `self`.
+            self.0.push(WitnessPat::wild_from_ctor(pcx.cx, ctor.clone(), pcx.ty.clone()));
+            fields
+                .into_iter()
+                .enumerate()
+                .filter(|(_, p)| !matches!(p.ctor(), Constructor::Wildcard))
+                .map(|(i, p)| {
+                    let mut ret = self.clone();
+                    // Fill the `i`th field of the union with `p`.
+                    ret.0.last_mut().unwrap().fields[i] = p;
+                    ret
+                })
+                .collect()
+        } else {
+            self.0.push(WitnessPat::new(ctor.clone(), fields, pcx.ty.clone()));
+            smallvec![self]
+        }
     }
 }
 
@@ -1459,8 +1485,8 @@ impl<Cx: PatCx> WitnessMatrix<Cx> {
             *self = ret;
         } else {
             // Any other constructor we unspecialize as expected.
-            for witness in self.0.iter_mut() {
-                witness.apply_constructor(pcx, ctor)
+            for witness in std::mem::take(&mut self.0) {
+                self.0.extend(witness.apply_constructor(pcx, ctor));
             }
         }
     }
@@ -1617,7 +1643,6 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>(
     };
 
     // Analyze the constructors present in this column.
-    debug!("ty: {:?}", place.ty);
     let ctors = matrix.heads().map(|p| p.ctor());
     let (split_ctors, missing_ctors) = place.split_column_ctors(mcx.tycx, ctors)?;
 
@@ -1669,7 +1694,10 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>(
     for row in matrix.rows() {
         if row.useful {
             if let PatOrWild::Pat(pat) = row.head() {
-                mcx.useful_subpatterns.insert(pat.uid);
+                let newly_useful = mcx.useful_subpatterns.insert(pat.uid);
+                if newly_useful {
+                    debug!("newly useful: {pat:?}");
+                }
             }
         }
     }
@@ -1768,6 +1796,7 @@ pub fn compute_match_usefulness<'p, Cx: PatCx>(
         .map(|arm| {
             debug!(?arm);
             let usefulness = collect_pattern_usefulness(&cx.useful_subpatterns, arm.pat);
+            debug!(?usefulness);
             (arm, usefulness)
         })
         .collect();
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 9f067273f35..f223f64f2c5 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -40,7 +40,7 @@ rustc_index::newtype_index! {
 }
 
 impl DepNodeIndex {
-    const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0);
+    const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::ZERO;
     pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1);
 }
 
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index b24ed573ff9..43a43e01a9a 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -605,6 +605,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 && !this.tcx.features().f16
                                 && !ident.span.allows_unstable(sym::f16)
                                 && finalize.is_some()
+                                && innermost_result.is_none()
                             {
                                 feature_err(
                                     this.tcx.sess,
@@ -618,6 +619,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 && !this.tcx.features().f128
                                 && !ident.span.allows_unstable(sym::f128)
                                 && finalize.is_some()
+                                && innermost_result.is_none()
                             {
                                 feature_err(
                                     this.tcx.sess,
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 48711f43518..76fe36a77cb 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -532,7 +532,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         let mut seen_spans = FxHashSet::default();
         let mut errors = vec![];
-        let mut prev_root_id: NodeId = NodeId::from_u32(0);
+        let mut prev_root_id: NodeId = NodeId::ZERO;
         let determined_imports = mem::take(&mut self.determined_imports);
         let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
 
@@ -556,8 +556,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                 }
 
-                if prev_root_id.as_u32() != 0
-                    && prev_root_id.as_u32() != import.root_id.as_u32()
+                if prev_root_id != NodeId::ZERO
+                    && prev_root_id != import.root_id
                     && !errors.is_empty()
                 {
                     // In the case of a new import line, throw a diagnostic message
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index 179fd79bef7..b8dacc6968d 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -96,6 +96,8 @@ session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto` or `-Cli
 
 session_sanitizer_cfi_requires_single_codegen_unit = `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`
 
+session_sanitizer_kcfi_requires_panic_abort = `-Z sanitizer=kcfi` requires `-C panic=abort`
+
 session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
 
 session_sanitizers_not_supported = {$us} sanitizers are not supported for this target
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index f612e8b5b1a..d51fcf693ed 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -990,22 +990,12 @@ bitflags::bitflags! {
         const MACRO = 1 << 0;
         /// Apply remappings to printed compiler diagnostics
         const DIAGNOSTICS = 1 << 1;
-        /// Apply remappings to debug information only when they are written to
-        /// compiled executables or libraries, but not when they are in split
-        /// debuginfo files
-        const UNSPLIT_DEBUGINFO = 1 << 2;
-        /// Apply remappings to debug information only when they are written to
-        /// split debug information files, but not in compiled executables or
-        /// libraries
-        const SPLIT_DEBUGINFO = 1 << 3;
-        /// Apply remappings to the paths pointing to split debug information
-        /// files. Does nothing when these files are not generated.
-        const SPLIT_DEBUGINFO_PATH = 1 << 4;
+        /// Apply remappings to debug informations
+        const DEBUGINFO = 1 << 3;
 
-        /// An alias for macro,unsplit-debuginfo,split-debuginfo-path. This
-        /// ensures all paths in compiled executables or libraries are remapped
-        /// but not elsewhere.
-        const OBJECT = Self::MACRO.bits() | Self::UNSPLIT_DEBUGINFO.bits() | Self::SPLIT_DEBUGINFO_PATH.bits();
+        /// An alias for `macro` and `debuginfo`. This ensures all paths in compiled
+        /// executables or libraries are remapped but not elsewhere.
+        const OBJECT = Self::MACRO.bits() | Self::DEBUGINFO.bits();
     }
 }
 
@@ -2010,7 +2000,7 @@ pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches
 }
 
 fn check_error_format_stability(
-    early_dcx: &mut EarlyDiagCtxt,
+    early_dcx: &EarlyDiagCtxt,
     unstable_opts: &UnstableOptions,
     error_format: ErrorOutputType,
 ) {
@@ -2108,7 +2098,7 @@ fn should_override_cgus_and_disable_thinlto(
 fn collect_print_requests(
     early_dcx: &EarlyDiagCtxt,
     cg: &mut CodegenOptions,
-    unstable_opts: &mut UnstableOptions,
+    unstable_opts: &UnstableOptions,
     matches: &getopts::Matches,
 ) -> Vec<PrintRequest> {
     let mut prints = Vec::<PrintRequest>::new();
@@ -2574,7 +2564,7 @@ fn parse_remap_path_prefix(
 }
 
 fn parse_logical_env(
-    early_dcx: &mut EarlyDiagCtxt,
+    early_dcx: &EarlyDiagCtxt,
     matches: &getopts::Matches,
 ) -> FxIndexMap<String, String> {
     let mut vars = FxIndexMap::default();
@@ -2732,6 +2722,8 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
     }
 
     if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
+        // FIXME: this is only mutation of UnstableOptions here, move into
+        // UnstableOptions::build?
         unstable_opts.graphviz_font = graphviz_font;
     }
 
@@ -2781,7 +2773,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
         ));
     }
 
-    let prints = collect_print_requests(early_dcx, &mut cg, &mut unstable_opts, matches);
+    let prints = collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches);
 
     let cg = cg;
 
@@ -2852,13 +2844,8 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
         early_dcx.early_fatal(format!("Current directory is invalid: {e}"));
     });
 
-    let remap = file_path_mapping(remap_path_prefix.clone(), &unstable_opts);
-    let (path, remapped) = remap.map_prefix(&working_dir);
-    let working_dir = if remapped {
-        RealFileName::Remapped { virtual_name: path.into_owned(), local_path: Some(working_dir) }
-    } else {
-        RealFileName::LocalPath(path.into_owned())
-    };
+    let file_mapping = file_path_mapping(remap_path_prefix.clone(), &unstable_opts);
+    let working_dir = file_mapping.to_real_filename(&working_dir);
 
     let verbose = matches.opt_present("verbose") || unstable_opts.verbose_internals;
 
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 0a855f87586..2e4c7d14ecd 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -146,6 +146,10 @@ pub(crate) struct SanitizerCfiGeneralizePointersRequiresCfi;
 pub(crate) struct SanitizerCfiNormalizeIntegersRequiresCfi;
 
 #[derive(Diagnostic)]
+#[diag(session_sanitizer_kcfi_requires_panic_abort)]
+pub(crate) struct SanitizerKcfiRequiresPanicAbort;
+
+#[derive(Diagnostic)]
 #[diag(session_split_lto_unit_requires_lto)]
 pub(crate) struct SplitLtoUnitRequiresLto;
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index b0bd5e75735..a76eb6b06aa 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -433,7 +433,8 @@ mod desc {
         "a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf`";
     pub const parse_proc_macro_execution_strategy: &str =
         "one of supported execution strategies (`same-thread`, or `cross-thread`)";
-    pub const parse_remap_path_scope: &str = "comma separated list of scopes: `macro`, `diagnostics`, `unsplit-debuginfo`, `split-debuginfo`, `split-debuginfo-path`, `object`, `all`";
+    pub const parse_remap_path_scope: &str =
+        "comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `object`, `all`";
     pub const parse_inlining_threshold: &str =
         "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number";
     pub const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)";
@@ -1156,9 +1157,7 @@ mod parse {
                 *slot |= match s {
                     "macro" => RemapPathScopeComponents::MACRO,
                     "diagnostics" => RemapPathScopeComponents::DIAGNOSTICS,
-                    "unsplit-debuginfo" => RemapPathScopeComponents::UNSPLIT_DEBUGINFO,
-                    "split-debuginfo" => RemapPathScopeComponents::SPLIT_DEBUGINFO,
-                    "split-debuginfo-path" => RemapPathScopeComponents::SPLIT_DEBUGINFO_PATH,
+                    "debuginfo" => RemapPathScopeComponents::DEBUGINFO,
                     "object" => RemapPathScopeComponents::OBJECT,
                     "all" => RemapPathScopeComponents::all(),
                     _ => return false,
@@ -1951,8 +1950,6 @@ written to standard error output)"),
     #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
     thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable ThinLTO when possible"),
-    thir_unsafeck: bool = (true, parse_bool, [TRACKED],
-        "use the THIR unsafety checker (default: yes)"),
     /// We default to 1 here since we want to behave like
     /// a sequential compiler for now. This'll likely be adjusted
     /// in the future. Note that -Zthreads=0 is the way to get
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index e6d82d6fab3..55fff4421ae 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -29,6 +29,7 @@ use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::{FileLoader, FilePathMapping, RealFileLoader, SourceMap};
+use rustc_span::{FileNameDisplayPreference, RealFileName};
 use rustc_span::{SourceFileHashAlgorithm, Span, Symbol};
 use rustc_target::asm::InlineAsmArch;
 use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
@@ -250,13 +251,8 @@ impl Session {
         self.miri_unleashed_features.lock().push((span, feature_gate));
     }
 
-    pub fn local_crate_source_file(&self) -> Option<PathBuf> {
-        let path = self.io.input.opt_path()?;
-        if self.should_prefer_remapped_for_codegen() {
-            Some(self.opts.file_path_mapping().map_prefix(path).0.into_owned())
-        } else {
-            Some(path.to_path_buf())
-        }
+    pub fn local_crate_source_file(&self) -> Option<RealFileName> {
+        Some(self.source_map().path_mapping().to_real_filename(self.io.input.opt_path()?))
     }
 
     fn check_miri_unleashed_features(&self) -> Option<ErrorGuaranteed> {
@@ -886,38 +882,19 @@ impl Session {
         self.opts.cg.link_dead_code.unwrap_or(false)
     }
 
-    pub fn should_prefer_remapped_for_codegen(&self) -> bool {
-        let has_split_debuginfo = match self.split_debuginfo() {
-            SplitDebuginfo::Off => false,
-            SplitDebuginfo::Packed => true,
-            SplitDebuginfo::Unpacked => true,
-        };
-
-        let remap_path_scopes = &self.opts.unstable_opts.remap_path_scope;
-        let mut prefer_remapped = false;
-
-        if remap_path_scopes.contains(RemapPathScopeComponents::UNSPLIT_DEBUGINFO) {
-            prefer_remapped |= !has_split_debuginfo;
-        }
-
-        if remap_path_scopes.contains(RemapPathScopeComponents::SPLIT_DEBUGINFO) {
-            prefer_remapped |= has_split_debuginfo;
+    pub fn filename_display_preference(
+        &self,
+        scope: RemapPathScopeComponents,
+    ) -> FileNameDisplayPreference {
+        assert!(
+            scope.bits().count_ones() == 1,
+            "one and only one scope should be passed to `Session::filename_display_preference`"
+        );
+        if self.opts.unstable_opts.remap_path_scope.contains(scope) {
+            FileNameDisplayPreference::Remapped
+        } else {
+            FileNameDisplayPreference::Local
         }
-
-        prefer_remapped
-    }
-
-    pub fn should_prefer_remapped_for_split_debuginfo_paths(&self) -> bool {
-        let has_split_debuginfo = match self.split_debuginfo() {
-            SplitDebuginfo::Off => false,
-            SplitDebuginfo::Packed | SplitDebuginfo::Unpacked => true,
-        };
-
-        self.opts
-            .unstable_opts
-            .remap_path_scope
-            .contains(RemapPathScopeComponents::SPLIT_DEBUGINFO_PATH)
-            && has_split_debuginfo
     }
 }
 
@@ -1234,6 +1211,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         sess.dcx().emit_err(errors::SanitizerCfiRequiresLto);
     }
 
+    // KCFI requires panic=abort
+    if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy() != PanicStrategy::Abort {
+        sess.dcx().emit_err(errors::SanitizerKcfiRequiresPanicAbort);
+    }
+
     // LLVM CFI using rustc LTO requires a single codegen unit.
     if sess.is_sanitizer_cfi_enabled()
         && sess.lto() == config::Lto::Fat
@@ -1469,12 +1451,8 @@ pub trait RemapFileNameExt {
 
     /// Returns a possibly remapped filename based on the passed scope and remap cli options.
     ///
-    /// One and only one scope should be passed to this method. For anything related to
-    /// "codegen" see the [`RemapFileNameExt::for_codegen`] method.
+    /// One and only one scope should be passed to this method, it will panic otherwise.
     fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_>;
-
-    /// Return a possibly remapped filename, to be used in "codegen" related parts.
-    fn for_codegen(&self, sess: &Session) -> Self::Output<'_>;
 }
 
 impl RemapFileNameExt for rustc_span::FileName {
@@ -1491,14 +1469,6 @@ impl RemapFileNameExt for rustc_span::FileName {
             self.prefer_local()
         }
     }
-
-    fn for_codegen(&self, sess: &Session) -> Self::Output<'_> {
-        if sess.should_prefer_remapped_for_codegen() {
-            self.prefer_remapped_unconditionaly()
-        } else {
-            self.prefer_local()
-        }
-    }
 }
 
 impl RemapFileNameExt for rustc_span::RealFileName {
@@ -1515,12 +1485,4 @@ impl RemapFileNameExt for rustc_span::RealFileName {
             self.local_path_if_available()
         }
     }
-
-    fn for_codegen(&self, sess: &Session) -> Self::Output<'_> {
-        if sess.should_prefer_remapped_for_codegen() {
-            self.remapped_path_if_available()
-        } else {
-            self.local_path_if_available()
-        }
-    }
 }
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index 50ebbdccf67..58de5cb31a5 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -127,7 +127,7 @@ pub fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
 
     const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &[&str] = &["incremental"];
 
-    let mut args = std::env::args_os().map(|arg| arg.to_string_lossy().to_string()).peekable();
+    let mut args = std::env::args_os().map(|arg| arg.to_string_lossy().to_string());
 
     let mut result = Vec::new();
     let mut excluded_cargo_defaults = false;
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index d39a3788d4c..7c12168b809 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -420,7 +420,10 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let tcx = tables.tcx;
         let args = args.internal(&mut *tables, tcx);
         let def_ty = tables.tcx.type_of(item.internal(&mut *tables, tcx));
-        def_ty.instantiate(tables.tcx, args).stable(&mut *tables)
+        tables
+            .tcx
+            .instantiate_and_normalize_erasing_regions(args, ty::ParamEnv::reveal_all(), def_ty)
+            .stable(&mut *tables)
     }
 
     fn const_pretty(&self, cnst: &stable_mir::ty::Const) -> String {
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index b6a722da602..c9f66612590 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -267,8 +267,8 @@ impl<'tcx> Stable<'tcx> for mir::CastKind {
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
         use rustc_middle::mir::CastKind::*;
         match self {
-            PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress,
-            PointerFromExposedAddress => stable_mir::mir::CastKind::PointerFromExposedAddress,
+            PointerExposeProvenance => stable_mir::mir::CastKind::PointerExposeAddress,
+            PointerWithExposedProvenance => stable_mir::mir::CastKind::PointerWithExposedProvenance,
             PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)),
             DynStar => stable_mir::mir::CastKind::DynStar,
             IntToInt => stable_mir::mir::CastKind::IntToInt,
@@ -493,6 +493,7 @@ impl<'tcx> Stable<'tcx> for mir::BinOp {
             BinOp::Ne => stable_mir::mir::BinOp::Ne,
             BinOp::Ge => stable_mir::mir::BinOp::Ge,
             BinOp::Gt => stable_mir::mir::BinOp::Gt,
+            BinOp::Cmp => stable_mir::mir::BinOp::Cmp,
             BinOp::Offset => stable_mir::mir::BinOp::Offset,
         }
     }
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 8f721bac951..8925b7a42d4 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -22,7 +22,7 @@ rustc_index::newtype_index! {
 
 /// Item definitions in the currently-compiled crate would have the `CrateNum`
 /// `LOCAL_CRATE` in their `DefId`.
-pub const LOCAL_CRATE: CrateNum = CrateNum::from_u32(0);
+pub const LOCAL_CRATE: CrateNum = CrateNum::ZERO;
 
 impl CrateNum {
     #[inline]
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 37fea6c122c..1df2b357ac1 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -165,7 +165,7 @@ pub enum Transparency {
 
 impl LocalExpnId {
     /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
-    pub const ROOT: LocalExpnId = LocalExpnId::from_u32(0);
+    pub const ROOT: LocalExpnId = LocalExpnId::ZERO;
 
     #[inline]
     fn from_raw(idx: ExpnIndex) -> LocalExpnId {
@@ -242,7 +242,7 @@ impl ExpnId {
     /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
     /// Invariant: we do not create any ExpnId with local_id == 0 and krate != 0.
     pub const fn root() -> ExpnId {
-        ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::from_u32(0) }
+        ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::ZERO }
     }
 
     #[inline]
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 0c974ef4ca3..7ce879807ca 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -271,6 +271,18 @@ impl RealFileName {
         }
     }
 
+    /// Return the path remmapped or not depending on the [`FileNameDisplayPreference`].
+    ///
+    /// For the purpose of this function, local and short preference are equal.
+    pub fn to_path(&self, display_pref: FileNameDisplayPreference) -> &Path {
+        match display_pref {
+            FileNameDisplayPreference::Local | FileNameDisplayPreference::Short => {
+                self.local_path_if_available()
+            }
+            FileNameDisplayPreference::Remapped => self.remapped_path_if_available(),
+        }
+    }
+
     pub fn to_string_lossy(&self, display_pref: FileNameDisplayPreference) -> Cow<'_, str> {
         match display_pref {
             FileNameDisplayPreference::Local => self.local_path_if_available().to_string_lossy(),
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index df7635e447d..770624d331d 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -1129,6 +1129,21 @@ impl FilePathMapping {
         }
     }
 
+    /// Applies any path prefix substitution as defined by the mapping.
+    /// The return value is the local path with a "virtual path" representing the remapped
+    /// part if any remapping was performed.
+    pub fn to_real_filename<'a>(&self, local_path: impl Into<Cow<'a, Path>>) -> RealFileName {
+        let local_path = local_path.into();
+        if let (remapped_path, true) = self.map_prefix(&*local_path) {
+            RealFileName::Remapped {
+                virtual_name: remapped_path.into_owned(),
+                local_path: Some(local_path.into_owned()),
+            }
+        } else {
+            RealFileName::LocalPath(local_path.into_owned())
+        }
+    }
+
     /// Expand a relative path to an absolute path with remapping taken into account.
     /// Use this when absolute paths are required (e.g. debuginfo or crate metadata).
     ///
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 81a9e470688..dcb02da3719 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -243,7 +243,7 @@ fn t10() {
         src_hash,
         stable_id,
         source_len.to_u32(),
-        CrateNum::new(0),
+        CrateNum::ZERO,
         FreezeLock::new(lines.read().clone()),
         multibyte_chars,
         non_narrow_chars,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 30f13daad57..a13c9c9b278 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -531,8 +531,15 @@ symbols! {
         cmp,
         cmp_max,
         cmp_min,
+        cmp_ord_max,
+        cmp_ord_min,
         cmp_partialeq_eq,
         cmp_partialeq_ne,
+        cmp_partialord_cmp,
+        cmp_partialord_ge,
+        cmp_partialord_gt,
+        cmp_partialord_le,
+        cmp_partialord_lt,
         cmpxchg16b_target_feature,
         cmse_nonsecure_entry,
         coerce_unsized,
@@ -1652,7 +1659,7 @@ symbols! {
         simd_cttz,
         simd_div,
         simd_eq,
-        simd_expose_addr,
+        simd_expose_provenance,
         simd_extract,
         simd_fabs,
         simd_fcos,
@@ -1668,7 +1675,6 @@ symbols! {
         simd_fmin,
         simd_fpow,
         simd_fpowi,
-        simd_from_exposed_addr,
         simd_fsin,
         simd_fsqrt,
         simd_gather,
@@ -1707,6 +1713,7 @@ symbols! {
         simd_shuffle_generic,
         simd_sub,
         simd_trunc,
+        simd_with_exposed_provenance,
         simd_xor,
         since,
         sinf128,
@@ -1806,6 +1813,7 @@ symbols! {
         thread,
         thread_local,
         thread_local_macro,
+        three_way_compare,
         thumb2,
         thumb_mode: "thumb-mode",
         tmm_reg,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 1c62ce2d214..f68668a91e6 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -2,7 +2,7 @@ use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{GenericArg, GenericArgKind};
 
 use std::fmt::{self, Write};
@@ -71,8 +71,14 @@ pub(super) fn mangle<'tcx>(
         ty::InstanceDef::VTableShim(..) => {
             printer.write_str("{{vtable-shim}}").unwrap();
         }
-        ty::InstanceDef::ReifyShim(..) => {
-            printer.write_str("{{reify-shim}}").unwrap();
+        ty::InstanceDef::ReifyShim(_, reason) => {
+            printer.write_str("{{reify-shim").unwrap();
+            match reason {
+                Some(ReifyReason::FnPtr) => printer.write_str("-fnptr").unwrap(),
+                Some(ReifyReason::Vtable) => printer.write_str("-vtable").unwrap(),
+                None => (),
+            }
+            printer.write_str("}}").unwrap();
         }
         // FIXME(async_closures): This shouldn't be needed when we fix
         // `Instance::ty`/`Instance::def_id`.
diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs
index fc1e8e46e8d..862ba285db8 100644
--- a/compiler/rustc_symbol_mangling/src/typeid.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid.rs
@@ -4,7 +4,7 @@
 /// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
 /// see design document in the tracking issue #89653.
 use bitflags::bitflags;
-use rustc_middle::ty::{Instance, Ty, TyCtxt};
+use rustc_middle::ty::{Instance, InstanceDef, ReifyReason, Ty, TyCtxt};
 use rustc_target::abi::call::FnAbi;
 use std::hash::Hasher;
 use twox_hash::XxHash64;
@@ -24,9 +24,9 @@ bitflags! {
         /// `-fsanitize-cfi-icall-experimental-normalize-integers` option for cross-language LLVM
         /// CFI and  KCFI support.
         const NORMALIZE_INTEGERS = 4;
-        /// Do not perform self type erasure for attaching a secondary type id to methods with their
-        /// concrete self so they can be used as function pointers.
-        const NO_SELF_TYPE_ERASURE = 8;
+        /// Generalize the instance by erasing the concrete `Self` type where possible.
+        /// Only has an effect on `{kcfi_,}typeid_for_instance`.
+        const ERASE_SELF_TYPE = 8;
     }
 }
 
@@ -67,8 +67,13 @@ pub fn kcfi_typeid_for_fnabi<'tcx>(
 pub fn kcfi_typeid_for_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
-    options: TypeIdOptions,
+    mut options: TypeIdOptions,
 ) -> u32 {
+    // If we receive a `ReifyShim` intended to produce a function pointer, we need to remain
+    // concrete - abstraction is for vtables.
+    if matches!(instance.def, InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr))) {
+        options.remove(TypeIdOptions::ERASE_SELF_TYPE);
+    }
     // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
     // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
     let mut hash: XxHash64 = Default::default();
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 7fd5cfeb48b..c632712f5a9 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -10,13 +10,15 @@
 use rustc_data_structures::base_n;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
+use rustc_hir::lang_items::LangItem;
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::layout::IntegerExt;
-use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{
     self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind,
     TermKind, Ty, TyCtxt, UintTy,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef};
+use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
 use rustc_span::def_id::DefId;
 use rustc_span::sym;
 use rustc_target::abi::call::{Conv, FnAbi, PassMode};
@@ -181,14 +183,15 @@ fn encode_fnsig<'tcx>(
     // Encode the return type
     let transform_ty_options = TransformTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
-    let ty = transform_ty(tcx, fn_sig.output(), &mut Vec::new(), transform_ty_options);
+    let mut type_folder = TransformTy::new(tcx, transform_ty_options);
+    let ty = fn_sig.output().fold_with(&mut type_folder);
     s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
 
     // Encode the parameter types
     let tys = fn_sig.inputs();
     if !tys.is_empty() {
         for ty in tys {
-            let ty = transform_ty(tcx, *ty, &mut Vec::new(), transform_ty_options);
+            let ty = ty.fold_with(&mut type_folder);
             s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
         }
 
@@ -522,15 +525,9 @@ fn encode_ty<'tcx>(
 
         ty::Array(ty0, len) => {
             // A<array-length><element-type>
+            let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
             let mut s = String::from("A");
-            let _ = write!(
-                s,
-                "{}",
-                &len.try_to_scalar()
-                    .unwrap()
-                    .to_target_usize(&tcx.data_layout)
-                    .expect("Array lens are defined in usize")
-            );
+            let _ = write!(s, "{}", &len);
             s.push_str(&encode_ty(tcx, *ty0, dict, options));
             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
             typeid.push_str(&s);
@@ -641,9 +638,7 @@ fn encode_ty<'tcx>(
         }
 
         // Function types
-        ty::FnDef(def_id, args)
-        | ty::Closure(def_id, args)
-        | ty::CoroutineClosure(def_id, args) => {
+        ty::FnDef(def_id, args) | ty::Closure(def_id, args) => {
             // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
             // as vendor extended type.
             let mut s = String::new();
@@ -654,6 +649,18 @@ fn encode_ty<'tcx>(
             typeid.push_str(&s);
         }
 
+        ty::CoroutineClosure(def_id, args) => {
+            // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
+            // as vendor extended type.
+            let mut s = String::new();
+            let name = encode_ty_name(tcx, *def_id);
+            let _ = write!(s, "u{}{}", name.len(), &name);
+            let parent_args = tcx.mk_args(args.as_coroutine_closure().parent_args());
+            s.push_str(&encode_args(tcx, parent_args, dict, options));
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
         ty::Coroutine(def_id, args, ..) => {
             // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
             // as vendor extended type.
@@ -745,278 +752,208 @@ fn encode_ty<'tcx>(
     typeid
 }
 
-/// Transforms predicates for being encoded and used in the substitution dictionary.
-fn transform_predicates<'tcx>(
+struct TransformTy<'tcx> {
     tcx: TyCtxt<'tcx>,
-    predicates: &List<ty::PolyExistentialPredicate<'tcx>>,
-) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> {
-    tcx.mk_poly_existential_predicates_from_iter(predicates.iter().filter_map(|predicate| {
-        match predicate.skip_binder() {
-            ty::ExistentialPredicate::Trait(trait_ref) => {
-                let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id);
-                Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait(
-                    ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
-                )))
-            }
-            ty::ExistentialPredicate::Projection(..) => None,
-            ty::ExistentialPredicate::AutoTrait(..) => Some(predicate),
-        }
-    }))
-}
-
-/// Transforms args for being encoded and used in the substitution dictionary.
-fn transform_args<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    args: GenericArgsRef<'tcx>,
-    parents: &mut Vec<Ty<'tcx>>,
     options: TransformTyOptions,
-) -> GenericArgsRef<'tcx> {
-    let args = args.iter().map(|arg| match arg.unpack() {
-        GenericArgKind::Type(ty) if ty.is_c_void(tcx) => Ty::new_unit(tcx).into(),
-        GenericArgKind::Type(ty) => transform_ty(tcx, ty, parents, options).into(),
-        _ => arg,
-    });
-    tcx.mk_args_from_iter(args)
+    parents: Vec<Ty<'tcx>>,
 }
 
-// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
-// c_void types into unit types unconditionally, generalizes pointers if
-// TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
-// TransformTyOptions::NORMALIZE_INTEGERS option is set.
-fn transform_ty<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    mut ty: Ty<'tcx>,
-    parents: &mut Vec<Ty<'tcx>>,
-    options: TransformTyOptions,
-) -> Ty<'tcx> {
-    match ty.kind() {
-        ty::Float(..) | ty::Str | ty::Never | ty::Foreign(..) | ty::CoroutineWitness(..) => {}
+impl<'tcx> TransformTy<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self {
+        TransformTy { tcx, options, parents: Vec::new() }
+    }
+}
 
-        ty::Bool => {
-            if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                // Note: on all platforms that Rust's currently supports, its size and alignment are
-                // 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
-                //
-                // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
-                //
-                // Clang represents bool as an 8-bit unsigned integer.
-                ty = tcx.types.u8;
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
+    // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms
+    // all c_void types into unit types unconditionally, generalizes pointers if
+    // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
+    // TransformTyOptions::NORMALIZE_INTEGERS option is set.
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        match t.kind() {
+            ty::Array(..)
+            | ty::Closure(..)
+            | ty::Coroutine(..)
+            | ty::CoroutineClosure(..)
+            | ty::CoroutineWitness(..)
+            | ty::Float(..)
+            | ty::FnDef(..)
+            | ty::Foreign(..)
+            | ty::Never
+            | ty::Slice(..)
+            | ty::Str
+            | ty::Tuple(..) => t.super_fold_with(self),
+
+            ty::Bool => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Note: on all platforms that Rust's currently supports, its size and alignment
+                    // are 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
+                    //
+                    // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
+                    //
+                    // Clang represents bool as an 8-bit unsigned integer.
+                    self.tcx.types.u8
+                } else {
+                    t
+                }
             }
-        }
 
-        ty::Char => {
-            if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                // Since #118032, char is guaranteed to have the same size, alignment, and function
-                // call ABI as u32 on all platforms.
-                ty = tcx.types.u32;
+            ty::Char => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Since #118032, char is guaranteed to have the same size, alignment, and
+                    // function call ABI as u32 on all platforms.
+                    self.tcx.types.u32
+                } else {
+                    t
+                }
             }
-        }
 
-        ty::Int(..) | ty::Uint(..) => {
-            if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit wide.
-                // All platforms we currently support have a C platform, and as a consequence,
-                // isize/usize are at least 16-bit wide for all of them.
-                //
-                // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
-                match ty.kind() {
-                    ty::Int(IntTy::Isize) => match tcx.sess.target.pointer_width {
-                        16 => ty = tcx.types.i16,
-                        32 => ty = tcx.types.i32,
-                        64 => ty = tcx.types.i64,
-                        128 => ty = tcx.types.i128,
-                        _ => bug!(
-                            "transform_ty: unexpected pointer width `{}`",
-                            tcx.sess.target.pointer_width
-                        ),
-                    },
-                    ty::Uint(UintTy::Usize) => match tcx.sess.target.pointer_width {
-                        16 => ty = tcx.types.u16,
-                        32 => ty = tcx.types.u32,
-                        64 => ty = tcx.types.u64,
-                        128 => ty = tcx.types.u128,
-                        _ => bug!(
-                            "transform_ty: unexpected pointer width `{}`",
-                            tcx.sess.target.pointer_width
-                        ),
-                    },
-                    _ => (),
+            ty::Int(..) | ty::Uint(..) => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit
+                    // wide. All platforms we currently support have a C platform, and as a
+                    // consequence, isize/usize are at least 16-bit wide for all of them.
+                    //
+                    // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
+                    match t.kind() {
+                        ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width {
+                            16 => self.tcx.types.i16,
+                            32 => self.tcx.types.i32,
+                            64 => self.tcx.types.i64,
+                            128 => self.tcx.types.i128,
+                            _ => bug!(
+                                "fold_ty: unexpected pointer width `{}`",
+                                self.tcx.sess.target.pointer_width
+                            ),
+                        },
+                        ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width {
+                            16 => self.tcx.types.u16,
+                            32 => self.tcx.types.u32,
+                            64 => self.tcx.types.u64,
+                            128 => self.tcx.types.u128,
+                            _ => bug!(
+                                "fold_ty: unexpected pointer width `{}`",
+                                self.tcx.sess.target.pointer_width
+                            ),
+                        },
+                        _ => t,
+                    }
+                } else {
+                    t
                 }
             }
-        }
-
-        _ if ty.is_unit() => {}
-
-        ty::Tuple(tys) => {
-            ty = Ty::new_tup_from_iter(
-                tcx,
-                tys.iter().map(|ty| transform_ty(tcx, ty, parents, options)),
-            );
-        }
-
-        ty::Array(ty0, len) => {
-            let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
 
-            ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, parents, options), len);
-        }
-
-        ty::Slice(ty0) => {
-            ty = Ty::new_slice(tcx, transform_ty(tcx, *ty0, parents, options));
-        }
+            ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit,
 
-        ty::Adt(adt_def, args) => {
-            if ty.is_c_void(tcx) {
-                ty = Ty::new_unit(tcx);
-            } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
-            {
-                ty = Ty::new_adt(tcx, *adt_def, ty::List::empty());
-            } else if adt_def.repr().transparent() && adt_def.is_struct() && !parents.contains(&ty)
-            {
-                // Don't transform repr(transparent) types with an user-defined CFI encoding to
-                // preserve the user-defined CFI encoding.
-                if let Some(_) = tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
-                    return ty;
-                }
-                let variant = adt_def.non_enum_variant();
-                let param_env = tcx.param_env(variant.def_id);
-                let field = variant.fields.iter().find(|field| {
-                    let ty = tcx.type_of(field.did).instantiate_identity();
-                    let is_zst =
-                        tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.is_zst());
-                    !is_zst
-                });
-                if let Some(field) = field {
-                    let ty0 = tcx.type_of(field.did).instantiate(tcx, args);
-                    // Generalize any repr(transparent) user-defined type that is either a pointer
-                    // or reference, and either references itself or any other type that contains or
-                    // references itself, to avoid a reference cycle.
-
-                    // If the self reference is not through a pointer, for example, due
-                    // to using `PhantomData`, need to skip normalizing it if we hit it again.
-                    parents.push(ty);
-                    if ty0.is_any_ptr() && ty0.contains(ty) {
-                        ty = transform_ty(
-                            tcx,
-                            ty0,
-                            parents,
-                            options | TransformTyOptions::GENERALIZE_POINTERS,
-                        );
+            ty::Adt(adt_def, args) => {
+                if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t)
+                {
+                    // Don't transform repr(transparent) types with an user-defined CFI encoding to
+                    // preserve the user-defined CFI encoding.
+                    if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
+                        return t;
+                    }
+                    let variant = adt_def.non_enum_variant();
+                    let param_env = self.tcx.param_env(variant.def_id);
+                    let field = variant.fields.iter().find(|field| {
+                        let ty = self.tcx.type_of(field.did).instantiate_identity();
+                        let is_zst = self
+                            .tcx
+                            .layout_of(param_env.and(ty))
+                            .is_ok_and(|layout| layout.is_zst());
+                        !is_zst
+                    });
+                    if let Some(field) = field {
+                        let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args);
+                        // Generalize any repr(transparent) user-defined type that is either a
+                        // pointer or reference, and either references itself or any other type that
+                        // contains or references itself, to avoid a reference cycle.
+
+                        // If the self reference is not through a pointer, for example, due
+                        // to using `PhantomData`, need to skip normalizing it if we hit it again.
+                        self.parents.push(t);
+                        let ty = if ty0.is_any_ptr() && ty0.contains(t) {
+                            let options = self.options;
+                            self.options |= TransformTyOptions::GENERALIZE_POINTERS;
+                            let ty = ty0.fold_with(self);
+                            self.options = options;
+                            ty
+                        } else {
+                            ty0.fold_with(self)
+                        };
+                        self.parents.pop();
+                        ty
                     } else {
-                        ty = transform_ty(tcx, ty0, parents, options);
+                        // Transform repr(transparent) types without non-ZST field into ()
+                        self.tcx.types.unit
                     }
-                    parents.pop();
                 } else {
-                    // Transform repr(transparent) types without non-ZST field into ()
-                    ty = Ty::new_unit(tcx);
+                    t.super_fold_with(self)
                 }
-            } else {
-                ty = Ty::new_adt(tcx, *adt_def, transform_args(tcx, args, parents, options));
             }
-        }
-
-        ty::FnDef(def_id, args) => {
-            ty = Ty::new_fn_def(tcx, *def_id, transform_args(tcx, args, parents, options));
-        }
 
-        ty::Closure(def_id, args) => {
-            ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, parents, options));
-        }
-
-        ty::CoroutineClosure(def_id, args) => {
-            ty = Ty::new_coroutine_closure(
-                tcx,
-                *def_id,
-                transform_args(tcx, args, parents, options),
-            );
-        }
-
-        ty::Coroutine(def_id, args) => {
-            ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, parents, options));
-        }
-
-        ty::Ref(region, ty0, ..) => {
-            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx));
-                } else {
-                    ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx));
-                }
-            } else {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options));
+            ty::Ref(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    if t.is_mutable_ptr() {
+                        Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
+                    } else {
+                        Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
+                    }
                 } else {
-                    ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options));
+                    t.super_fold_with(self)
                 }
             }
-        }
 
-        ty::RawPtr(ptr_ty, _) => {
-            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx));
+            ty::RawPtr(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    if t.is_mutable_ptr() {
+                        Ty::new_mut_ptr(self.tcx, self.tcx.types.unit)
+                    } else {
+                        Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
+                    }
                 } else {
-                    ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx));
+                    t.super_fold_with(self)
                 }
-            } else {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options));
+            }
+
+            ty::FnPtr(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
                 } else {
-                    ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options));
+                    t.super_fold_with(self)
                 }
             }
-        }
 
-        ty::FnPtr(fn_sig) => {
-            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx));
-            } else {
-                let parameters: Vec<Ty<'tcx>> = fn_sig
-                    .skip_binder()
-                    .inputs()
-                    .iter()
-                    .map(|ty| transform_ty(tcx, *ty, parents, options))
-                    .collect();
-                let output = transform_ty(tcx, fn_sig.skip_binder().output(), parents, options);
-                ty = Ty::new_fn_ptr(
-                    tcx,
-                    ty::Binder::bind_with_vars(
-                        tcx.mk_fn_sig(
-                            parameters,
-                            output,
-                            fn_sig.c_variadic(),
-                            fn_sig.unsafety(),
-                            fn_sig.abi(),
-                        ),
-                        fn_sig.bound_vars(),
-                    ),
+            ty::Dynamic(predicates, _region, kind) => {
+                let predicates = self.tcx.mk_poly_existential_predicates_from_iter(
+                    predicates.iter().filter_map(|predicate| match predicate.skip_binder() {
+                        ty::ExistentialPredicate::Trait(trait_ref) => {
+                            let trait_ref = ty::TraitRef::identity(self.tcx, trait_ref.def_id);
+                            Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait(
+                                ty::ExistentialTraitRef::erase_self_ty(self.tcx, trait_ref),
+                            )))
+                        }
+                        ty::ExistentialPredicate::Projection(..) => None,
+                        ty::ExistentialPredicate::AutoTrait(..) => Some(predicate),
+                    }),
                 );
-            }
-        }
 
-        ty::Dynamic(predicates, _region, kind) => {
-            ty = Ty::new_dynamic(
-                tcx,
-                transform_predicates(tcx, predicates),
-                tcx.lifetimes.re_erased,
-                *kind,
-            );
-        }
+                Ty::new_dynamic(self.tcx, predicates, self.tcx.lifetimes.re_erased, *kind)
+            }
 
-        ty::Alias(..) => {
-            ty = transform_ty(
-                tcx,
-                tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty),
-                parents,
-                options,
-            );
-        }
+            ty::Alias(..) => {
+                self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t))
+            }
 
-        ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
-            bug!("transform_ty: unexpected `{:?}`", ty.kind());
+            ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
+                bug!("fold_ty: unexpected `{:?}`", t.kind());
+            }
         }
     }
 
-    ty
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
 }
 
 /// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
@@ -1057,7 +994,8 @@ pub fn typeid_for_fnabi<'tcx>(
     // Encode the return type
     let transform_ty_options = TransformTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
-    let ty = transform_ty(tcx, fn_abi.ret.layout.ty, &mut Vec::new(), transform_ty_options);
+    let mut type_folder = TransformTy::new(tcx, transform_ty_options);
+    let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder);
     typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
 
     // Encode the parameter types
@@ -1069,7 +1007,7 @@ pub fn typeid_for_fnabi<'tcx>(
         let mut pushed_arg = false;
         for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) {
             pushed_arg = true;
-            let ty = transform_ty(tcx, arg.layout.ty, &mut Vec::new(), transform_ty_options);
+            let ty = arg.layout.ty.fold_with(&mut type_folder);
             typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
         }
         if !pushed_arg {
@@ -1082,8 +1020,7 @@ pub fn typeid_for_fnabi<'tcx>(
             if fn_abi.args[n].mode == PassMode::Ignore {
                 continue;
             }
-            let ty =
-                transform_ty(tcx, fn_abi.args[n].layout.ty, &mut Vec::new(), transform_ty_options);
+            let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder);
             typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
         }
 
@@ -1140,45 +1077,115 @@ pub fn typeid_for_instance<'tcx>(
         let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
         let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
         instance.args = tcx.mk_args_trait(self_ty, List::empty());
-    } else if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
-        instance.args = strip_receiver_auto(tcx, instance.args);
+    } else if let ty::InstanceDef::Virtual(def_id, _) = instance.def {
+        let upcast_ty = match tcx.trait_of_item(def_id) {
+            Some(trait_id) => trait_object_ty(
+                tcx,
+                ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)),
+            ),
+            // drop_in_place won't have a defining trait, skip the upcast
+            None => instance.args.type_at(0),
+        };
+        let stripped_ty = strip_receiver_auto(tcx, upcast_ty);
+        instance.args = tcx.mk_args_trait(stripped_ty, instance.args.into_iter().skip(1));
+    } else if let ty::InstanceDef::VTableShim(def_id) = instance.def
+        && let Some(trait_id) = tcx.trait_of_item(def_id)
+    {
+        // VTableShims may have a trait method, but a concrete Self. This is not suitable for a vtable,
+        // as the caller will not know the concrete Self.
+        let trait_ref = ty::TraitRef::new(tcx, trait_id, instance.args);
+        let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
+        instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
     }
 
-    if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE)
-        && let Some(impl_id) = tcx.impl_of_method(instance.def_id())
-        && let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
-    {
-        let impl_method = tcx.associated_item(instance.def_id());
-        let method_id = impl_method
-            .trait_item_def_id
-            .expect("Part of a trait implementation, but not linked to the def_id?");
-        let trait_method = tcx.associated_item(method_id);
-        let trait_id = trait_ref.skip_binder().def_id;
-        if traits::is_vtable_safe_method(tcx, trait_id, trait_method)
-            && tcx.object_safety_violations(trait_id).is_empty()
+    if options.contains(EncodeTyOptions::ERASE_SELF_TYPE) {
+        if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
+            && let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
         {
-            // Trait methods will have a Self polymorphic parameter, where the concreteized
-            // implementatation will not. We need to walk back to the more general trait method
-            let trait_ref = tcx.instantiate_and_normalize_erasing_regions(
-                instance.args,
-                ty::ParamEnv::reveal_all(),
-                trait_ref,
-            );
+            let impl_method = tcx.associated_item(instance.def_id());
+            let method_id = impl_method
+                .trait_item_def_id
+                .expect("Part of a trait implementation, but not linked to the def_id?");
+            let trait_method = tcx.associated_item(method_id);
+            let trait_id = trait_ref.skip_binder().def_id;
+            if traits::is_vtable_safe_method(tcx, trait_id, trait_method)
+                && tcx.object_safety_violations(trait_id).is_empty()
+            {
+                // Trait methods will have a Self polymorphic parameter, where the concreteized
+                // implementatation will not. We need to walk back to the more general trait method
+                let trait_ref = tcx.instantiate_and_normalize_erasing_regions(
+                    instance.args,
+                    ty::ParamEnv::reveal_all(),
+                    trait_ref,
+                );
+                let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
+
+                // At the call site, any call to this concrete function through a vtable will be
+                // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
+                // original method id, and we've recovered the trait arguments, we can make the callee
+                // instance we're computing the alias set for match the caller instance.
+                //
+                // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
+                // If we ever *do* start encoding the vtable index, we will need to generate an alias set
+                // based on which vtables we are putting this method into, as there will be more than one
+                // index value when supertraits are involved.
+                instance.def = ty::InstanceDef::Virtual(method_id, 0);
+                let abstract_trait_args =
+                    tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
+                instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args);
+            }
+        } else if tcx.is_closure_like(instance.def_id()) {
+            // We're either a closure or a coroutine. Our goal is to find the trait we're defined on,
+            // instantiate it, and take the type of its only method as our own.
+            let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
+            let (trait_id, inputs) = match closure_ty.kind() {
+                ty::Closure(..) => {
+                    let closure_args = instance.args.as_closure();
+                    let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap();
+                    let tuple_args =
+                        tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0];
+                    (trait_id, Some(tuple_args))
+                }
+                ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() {
+                    hir::CoroutineKind::Coroutine(..) => (
+                        tcx.require_lang_item(LangItem::Coroutine, None),
+                        Some(instance.args.as_coroutine().resume_ty()),
+                    ),
+                    hir::CoroutineKind::Desugared(desugaring, _) => {
+                        let lang_item = match desugaring {
+                            hir::CoroutineDesugaring::Async => LangItem::Future,
+                            hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator,
+                            hir::CoroutineDesugaring::Gen => LangItem::Iterator,
+                        };
+                        (tcx.require_lang_item(lang_item, None), None)
+                    }
+                },
+                ty::CoroutineClosure(..) => (
+                    tcx.require_lang_item(LangItem::FnOnce, None),
+                    Some(
+                        tcx.instantiate_bound_regions_with_erased(
+                            instance.args.as_coroutine_closure().coroutine_closure_sig(),
+                        )
+                        .tupled_inputs_ty,
+                    ),
+                ),
+                x => bug!("Unexpected type kind for closure-like: {x:?}"),
+            };
+            let concrete_args = tcx.mk_args_trait(closure_ty, inputs.map(Into::into));
+            let trait_ref = ty::TraitRef::new(tcx, trait_id, concrete_args);
             let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
+            let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
+            // There should be exactly one method on this trait, and it should be the one we're
+            // defining.
+            let call = tcx
+                .associated_items(trait_id)
+                .in_definition_order()
+                .find(|it| it.kind == ty::AssocKind::Fn)
+                .expect("No call-family function on closure-like Fn trait?")
+                .def_id;
 
-            // At the call site, any call to this concrete function through a vtable will be
-            // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
-            // original method id, and we've recovered the trait arguments, we can make the callee
-            // instance we're computing the alias set for match the caller instance.
-            //
-            // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
-            // If we ever *do* start encoding the vtable index, we will need to generate an alias set
-            // based on which vtables we are putting this method into, as there will be more than one
-            // index value when supertraits are involved.
-            instance.def = ty::InstanceDef::Virtual(method_id, 0);
-            let abstract_trait_args =
-                tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
-            instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args);
+            instance.def = ty::InstanceDef::Virtual(call, 0);
+            instance.args = abstract_args;
         }
     }
 
@@ -1191,15 +1198,11 @@ pub fn typeid_for_instance<'tcx>(
     typeid_for_fnabi(tcx, fn_abi, options)
 }
 
-fn strip_receiver_auto<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    args: ty::GenericArgsRef<'tcx>,
-) -> ty::GenericArgsRef<'tcx> {
-    let ty = args.type_at(0);
+fn strip_receiver_auto<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
     let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
         bug!("Tried to strip auto traits from non-dynamic type {ty}");
     };
-    let new_rcvr = if preds.principal().is_some() {
+    if preds.principal().is_some() {
         let filtered_preds =
             tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
                 !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
@@ -1210,8 +1213,7 @@ fn strip_receiver_auto<'tcx>(
         // about it. This technically discards the knowledge that it was a type that was made
         // into a trait object at some point, but that's not a lot.
         tcx.types.unit
-    };
-    tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1))
+    }
 }
 
 #[instrument(skip(tcx), ret)]
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 4369f020d27..8cb5370bb4a 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -8,8 +8,8 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::print::{Print, PrintError, Printer};
 use rustc_middle::ty::{
-    self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, TypeVisitableExt,
-    UintTy,
+    self, EarlyBinder, FloatTy, Instance, IntTy, ReifyReason, Ty, TyCtxt, TypeVisitable,
+    TypeVisitableExt, UintTy,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
 use rustc_span::symbol::kw;
@@ -44,7 +44,9 @@ pub(super) fn mangle<'tcx>(
     let shim_kind = match instance.def {
         ty::InstanceDef::ThreadLocalShim(_) => Some("tls"),
         ty::InstanceDef::VTableShim(_) => Some("vtable"),
-        ty::InstanceDef::ReifyShim(_) => Some("reify"),
+        ty::InstanceDef::ReifyShim(_, None) => Some("reify"),
+        ty::InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify-fnptr"),
+        ty::InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify-vtable"),
 
         ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
         | ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"),
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 486afc5f8f3..cdd3f0afd79 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -251,9 +251,9 @@ pub struct Uniform {
     /// The total size of the argument, which can be:
     /// * equal to `unit.size` (one scalar/vector),
     /// * a multiple of `unit.size` (an array of scalar/vectors),
-    /// * if `unit.kind` is `Integer`, the last element
-    ///   can be shorter, i.e., `{ i64, i64, i32 }` for
-    ///   64-bit integers with a total size of 20 bytes.
+    /// * if `unit.kind` is `Integer`, the last element can be shorter, i.e., `{ i64, i64, i32 }`
+    ///   for 64-bit integers with a total size of 20 bytes. When the argument is actually passed,
+    ///   this size will be rounded up to the nearest multiple of `unit.size`.
     pub total: Size,
 }
 
@@ -319,14 +319,17 @@ impl CastTarget {
     }
 
     pub fn size<C: HasDataLayout>(&self, _cx: &C) -> Size {
-        let mut size = self.rest.total;
-        for i in 0..self.prefix.iter().count() {
-            match self.prefix[i] {
-                Some(v) => size += v.size,
-                None => {}
-            }
-        }
-        return size;
+        // Prefix arguments are passed in specific designated registers
+        let prefix_size = self
+            .prefix
+            .iter()
+            .filter_map(|x| x.map(|reg| reg.size))
+            .fold(Size::ZERO, |acc, size| acc + size);
+        // Remaining arguments are passed in chunks of the unit size
+        let rest_size =
+            self.rest.unit.size * self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes());
+
+        prefix_size + rest_size
     }
 
     pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
@@ -927,7 +930,7 @@ impl FromStr for Conv {
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index f694dd00703..7056288e758 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -49,8 +49,7 @@ impl<'tcx> InferCtxt<'tcx> {
     /// - the parameter environment
     ///
     /// Invokes `evaluate_obligation`, so in the event that evaluating
-    /// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent
-    /// (or EvaluatedToAmbigStackDependent) will be returned.
+    /// `Ty: Trait` causes overflow, EvaluatedToAmbigStackDependent will be returned.
     #[instrument(level = "debug", skip(self, params), ret)]
     fn type_implements_trait(
         &self,
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index e14fc62cd6f..b5fb710e4cc 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -30,7 +30,7 @@
 
 #[macro_use]
 extern crate rustc_macros;
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 #[macro_use]
 extern crate rustc_data_structures;
 #[macro_use]
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 66688893235..d8aeadd07b3 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -1,4 +1,4 @@
-use crate::traits::{check_args_compatible, specialization_graph};
+use crate::traits::specialization_graph;
 
 use super::assembly::structural_traits::AsyncCallableRelevantTypes;
 use super::assembly::{self, structural_traits, Candidate};
@@ -247,7 +247,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 assoc_def.defining_node,
             );
 
-            if !check_args_compatible(tcx, assoc_def.item, args) {
+            if !tcx.check_args_compatible(assoc_def.item.def_id, args) {
                 return error_response(
                     ecx,
                     "associated item has mismatched generic item arguments",
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index c909a0b49e2..73e94da165f 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -6,13 +6,13 @@ use super::*;
 use crate::errors::UnableToConstructConstantValue;
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::traits::project::ProjectAndUnifyResult;
+
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
+use rustc_data_structures::unord::UnordSet;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::{Region, RegionVid};
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
-
-use std::collections::hash_map::Entry;
 use std::collections::VecDeque;
 use std::iter;
 
@@ -25,8 +25,8 @@ pub enum RegionTarget<'tcx> {
 
 #[derive(Default, Debug, Clone)]
 pub struct RegionDeps<'tcx> {
-    larger: FxIndexSet<RegionTarget<'tcx>>,
-    smaller: FxIndexSet<RegionTarget<'tcx>>,
+    pub larger: FxIndexSet<RegionTarget<'tcx>>,
+    pub smaller: FxIndexSet<RegionTarget<'tcx>>,
 }
 
 pub enum AutoTraitResult<A> {
@@ -35,17 +35,10 @@ pub enum AutoTraitResult<A> {
     NegativeImpl,
 }
 
-#[allow(dead_code)]
-impl<A> AutoTraitResult<A> {
-    fn is_auto(&self) -> bool {
-        matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl)
-    }
-}
-
 pub struct AutoTraitInfo<'cx> {
     pub full_user_env: ty::ParamEnv<'cx>,
     pub region_data: RegionConstraintData<'cx>,
-    pub vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'cx>>,
+    pub vid_to_region: FxIndexMap<ty::RegionVid, ty::Region<'cx>>,
 }
 
 pub struct AutoTraitFinder<'tcx> {
@@ -88,19 +81,12 @@ impl<'tcx> AutoTraitFinder<'tcx> {
 
         let infcx = tcx.infer_ctxt().build();
         let mut selcx = SelectionContext::new(&infcx);
-        for polarity in [true, false] {
+        for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] {
             let result = selcx.select(&Obligation::new(
                 tcx,
                 ObligationCause::dummy(),
                 orig_env,
-                ty::TraitPredicate {
-                    trait_ref,
-                    polarity: if polarity {
-                        ty::PredicatePolarity::Positive
-                    } else {
-                        ty::PredicatePolarity::Negative
-                    },
-                },
+                ty::TraitPredicate { trait_ref, polarity },
             ));
             if let Ok(Some(ImplSource::UserDefined(_))) = result {
                 debug!(
@@ -114,7 +100,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         }
 
         let infcx = tcx.infer_ctxt().build();
-        let mut fresh_preds = FxHashSet::default();
+        let mut fresh_preds = FxIndexSet::default();
 
         // Due to the way projections are handled by SelectionContext, we need to run
         // evaluate_predicates twice: once on the original param env, and once on the result of
@@ -239,7 +225,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         ty: Ty<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         user_env: ty::ParamEnv<'tcx>,
-        fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
+        fresh_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
     ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> {
         let tcx = infcx.tcx;
 
@@ -252,7 +238,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
 
         let mut select = SelectionContext::new(infcx);
 
-        let mut already_visited = FxHashSet::default();
+        let mut already_visited = UnordSet::new();
         let mut predicates = VecDeque::new();
         predicates.push_back(ty::Binder::dummy(ty::TraitPredicate {
             trait_ref: ty::TraitRef::new(infcx.tcx, trait_did, [ty]),
@@ -473,9 +459,9 @@ impl<'tcx> AutoTraitFinder<'tcx> {
     fn map_vid_to_region<'cx>(
         &self,
         regions: &RegionConstraintData<'cx>,
-    ) -> FxHashMap<ty::RegionVid, ty::Region<'cx>> {
-        let mut vid_map: FxHashMap<RegionTarget<'cx>, RegionDeps<'cx>> = FxHashMap::default();
-        let mut finished_map = FxHashMap::default();
+    ) -> FxIndexMap<ty::RegionVid, ty::Region<'cx>> {
+        let mut vid_map = FxIndexMap::<RegionTarget<'cx>, RegionDeps<'cx>>::default();
+        let mut finished_map = FxIndexMap::default();
 
         for (constraint, _) in &regions.constraints {
             match constraint {
@@ -513,25 +499,22 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         }
 
         while !vid_map.is_empty() {
-            #[allow(rustc::potential_query_instability)]
-            let target = *vid_map.keys().next().expect("Keys somehow empty");
-            let deps = vid_map.remove(&target).expect("Entry somehow missing");
+            let target = *vid_map.keys().next().unwrap();
+            let deps = vid_map.swap_remove(&target).unwrap();
 
             for smaller in deps.smaller.iter() {
                 for larger in deps.larger.iter() {
                     match (smaller, larger) {
                         (&RegionTarget::Region(_), &RegionTarget::Region(_)) => {
-                            if let Entry::Occupied(v) = vid_map.entry(*smaller) {
+                            if let IndexEntry::Occupied(v) = vid_map.entry(*smaller) {
                                 let smaller_deps = v.into_mut();
                                 smaller_deps.larger.insert(*larger);
-                                // FIXME(#120456) - is `swap_remove` correct?
                                 smaller_deps.larger.swap_remove(&target);
                             }
 
-                            if let Entry::Occupied(v) = vid_map.entry(*larger) {
+                            if let IndexEntry::Occupied(v) = vid_map.entry(*larger) {
                                 let larger_deps = v.into_mut();
                                 larger_deps.smaller.insert(*smaller);
-                                // FIXME(#120456) - is `swap_remove` correct?
                                 larger_deps.smaller.swap_remove(&target);
                             }
                         }
@@ -542,17 +525,15 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                             // Do nothing; we don't care about regions that are smaller than vids.
                         }
                         (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => {
-                            if let Entry::Occupied(v) = vid_map.entry(*smaller) {
+                            if let IndexEntry::Occupied(v) = vid_map.entry(*smaller) {
                                 let smaller_deps = v.into_mut();
                                 smaller_deps.larger.insert(*larger);
-                                // FIXME(#120456) - is `swap_remove` correct?
                                 smaller_deps.larger.swap_remove(&target);
                             }
 
-                            if let Entry::Occupied(v) = vid_map.entry(*larger) {
+                            if let IndexEntry::Occupied(v) = vid_map.entry(*larger) {
                                 let larger_deps = v.into_mut();
                                 larger_deps.smaller.insert(*smaller);
-                                // FIXME(#120456) - is `swap_remove` correct?
                                 larger_deps.smaller.swap_remove(&target);
                             }
                         }
@@ -560,6 +541,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 }
             }
         }
+
         finished_map
     }
 
@@ -588,7 +570,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         ty: Ty<'_>,
         nested: impl Iterator<Item = PredicateObligation<'tcx>>,
         computed_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
-        fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
+        fresh_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
         predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>,
         selcx: &mut SelectionContext<'_, 'tcx>,
     ) -> bool {
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 2712ba19451..90e337a53b6 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -210,7 +210,7 @@ fn overlap<'tcx>(
         .intercrate(true)
         .with_next_trait_solver(tcx.next_trait_solver_in_coherence())
         .build();
-    let selcx = &mut SelectionContext::with_treat_inductive_cycle_as_ambig(&infcx);
+    let selcx = &mut SelectionContext::new(&infcx);
     if track_ambiguity_causes.is_yes() {
         selcx.enable_tracking_intercrate_ambiguity_causes();
     }
@@ -554,11 +554,7 @@ fn plug_infer_with_placeholders<'tcx>(
         }
     }
 
-    value.visit_with(&mut PlugInferWithPlaceholder {
-        infcx,
-        universe,
-        var: ty::BoundVar::from_u32(0),
-    });
+    value.visit_with(&mut PlugInferWithPlaceholder { infcx, universe, var: ty::BoundVar::ZERO });
 }
 
 fn try_prove_negated_where_clause<'tcx>(
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 28f4f81e7d8..fe2691e9d4d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -4931,7 +4931,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
         let hir::WherePredicate::BoundPredicate(pred) = pred else {
             continue;
         };
-        let mut bounds = pred.bounds.iter().peekable();
+        let mut bounds = pred.bounds.iter();
         while let Some(bound) = bounds.next() {
             let Some(trait_ref) = bound.trait_ref() else {
                 continue;
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 7a62030353d..aef98dbad5f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -1128,10 +1128,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         err: &mut Diag<'_>,
     ) -> bool {
         let span = obligation.cause.span;
-        struct V {
+        /// Look for the (direct) sub-expr of `?`, and return it if it's a `.` method call.
+        struct FindMethodSubexprOfTry {
             search_span: Span,
         }
-        impl<'v> Visitor<'v> for V {
+        impl<'v> Visitor<'v> for FindMethodSubexprOfTry {
             type Result = ControlFlow<&'v hir::Expr<'v>>;
             fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> Self::Result {
                 if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind
@@ -1149,8 +1150,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) => body_id,
             _ => return false,
         };
-        let ControlFlow::Break(expr) =
-            (V { search_span: span }).visit_body(self.tcx.hir().body(*body_id))
+        let ControlFlow::Break(expr) = (FindMethodSubexprOfTry { search_span: span })
+            .visit_body(self.tcx.hir().body(*body_id))
         else {
             return false;
         };
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 34c891d400e..b5be9a2bcb3 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -72,7 +72,7 @@ pub struct PendingPredicateObligation<'tcx> {
 }
 
 // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(PendingPredicateObligation<'_>, 72);
 
 impl<'tcx> FulfillmentContext<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index c875d3da47e..2c8116b779b 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -61,12 +61,12 @@ pub use self::specialize::{
 pub use self::structural_match::search_for_structural_match_violation;
 pub use self::structural_normalize::StructurallyNormalizeExt;
 pub use self::util::elaborate;
+pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};
+pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
 pub use self::util::{
-    check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds,
-    transitive_bounds_that_define_assoc_item, SupertraitDefIds,
+    supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item,
+    SupertraitDefIds,
 };
-pub use self::util::{expand_trait_aliases, TraitAliasExpander};
-pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
 pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
 
 pub use rustc_infer::traits::*;
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 12371155303..9d744d9a032 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -2,7 +2,6 @@
 
 use std::ops::ControlFlow;
 
-use super::check_args_compatible;
 use super::specialization_graph;
 use super::translate_args;
 use super::util;
@@ -508,7 +507,7 @@ pub(super) fn opt_normalize_projection_type<'a, 'b, 'tcx>(
 /// because it contains `[type error]`. Yuck! (See issue #29857 for
 /// one case where this arose.)
 fn normalize_to_error<'a, 'tcx>(
-    selcx: &mut SelectionContext<'a, 'tcx>,
+    selcx: &SelectionContext<'a, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     projection_ty: ty::AliasTy<'tcx>,
     cause: ObligationCause<'tcx>,
@@ -2030,7 +2029,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     } else {
         ty.map_bound(|ty| ty.into())
     };
-    if !check_args_compatible(tcx, assoc_ty.item, args) {
+    if !tcx.check_args_compatible(assoc_ty.item.def_id, args) {
         let err = Ty::new_error_with_message(
             tcx,
             obligation.cause.span,
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 6f512a1173f..0459246553b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -28,7 +28,7 @@ use crate::traits::{
     BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
     ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, PolyTraitObligation,
     PredicateObligation, Selection, SelectionError, SignatureMismatch, TraitNotObjectSafe,
-    Unimplemented,
+    TraitObligation, Unimplemented,
 };
 
 use super::BuiltinImplConditions;
@@ -678,17 +678,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         fn_host_effect: ty::Const<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
         debug!(?obligation, "confirm_fn_pointer_candidate");
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
 
         let tcx = self.tcx();
-
-        let Some(self_ty) = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars()) else {
-            // FIXME: Ideally we'd support `for<'a> fn(&'a ()): Fn(&'a ())`,
-            // but we do not currently. Luckily, such a bound is not
-            // particularly useful, so we don't expect users to write
-            // them often.
-            return Err(SelectionError::Unimplemented);
-        };
-
         let sig = self_ty.fn_sig(tcx);
         let trait_ref = closure_trait_ref_and_return_type(
             tcx,
@@ -700,7 +693,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         )
         .map_bound(|(trait_ref, _)| trait_ref);
 
-        let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+        let mut nested =
+            self.equate_trait_refs(obligation.with(tcx, placeholder_predicate), trait_ref)?;
         let cause = obligation.derived_cause(BuiltinDerivedObligation);
 
         // Confirm the `type Output: Sized;` bound that is present on `FnOnce`
@@ -748,10 +742,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // Okay to skip binder because the args on coroutine types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
@@ -760,15 +752,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let coroutine_sig = args.as_coroutine().sig();
 
-        // NOTE: The self-type is a coroutine type and hence is
-        // in fact unparameterized (or at least does not reference any
-        // regions bound in the obligation).
-        let self_ty = obligation
-            .predicate
-            .self_ty()
-            .no_bound_vars()
-            .expect("unboxed closure type should not capture bound vars from the predicate");
-
         let (trait_ref, _, _) = super::util::coroutine_trait_ref_and_outputs(
             self.tcx(),
             obligation.predicate.def_id(),
@@ -776,7 +759,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             coroutine_sig,
         );
 
-        let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
+        let nested = self.equate_trait_refs(
+            obligation.with(self.tcx(), placeholder_predicate),
+            ty::Binder::dummy(trait_ref),
+        )?;
         debug!(?trait_ref, ?nested, "coroutine candidate obligations");
 
         Ok(nested)
@@ -786,10 +772,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // Okay to skip binder because the args on coroutine types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
@@ -801,11 +785,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let (trait_ref, _) = super::util::future_trait_ref_and_outputs(
             self.tcx(),
             obligation.predicate.def_id(),
-            obligation.predicate.no_bound_vars().expect("future has no bound vars").self_ty(),
+            self_ty,
             coroutine_sig,
         );
 
-        let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
+        let nested = self.equate_trait_refs(
+            obligation.with(self.tcx(), placeholder_predicate),
+            ty::Binder::dummy(trait_ref),
+        )?;
         debug!(?trait_ref, ?nested, "future candidate obligations");
 
         Ok(nested)
@@ -815,10 +802,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // Okay to skip binder because the args on coroutine types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
@@ -830,11 +815,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let (trait_ref, _) = super::util::iterator_trait_ref_and_outputs(
             self.tcx(),
             obligation.predicate.def_id(),
-            obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(),
+            self_ty,
             gen_sig,
         );
 
-        let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
+        let nested = self.equate_trait_refs(
+            obligation.with(self.tcx(), placeholder_predicate),
+            ty::Binder::dummy(trait_ref),
+        )?;
         debug!(?trait_ref, ?nested, "iterator candidate obligations");
 
         Ok(nested)
@@ -844,10 +832,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // Okay to skip binder because the args on coroutine types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
@@ -859,11 +845,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let (trait_ref, _) = super::util::async_iterator_trait_ref_and_outputs(
             self.tcx(),
             obligation.predicate.def_id(),
-            obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(),
+            self_ty,
             gen_sig,
         );
 
-        let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
+        let nested = self.equate_trait_refs(
+            obligation.with(self.tcx(), placeholder_predicate),
+            ty::Binder::dummy(trait_ref),
+        )?;
         debug!(?trait_ref, ?nested, "iterator candidate obligations");
 
         Ok(nested)
@@ -874,14 +863,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // Okay to skip binder because the args on closure types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty: Ty<'_> = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
+
         let trait_ref = match *self_ty.kind() {
-            ty::Closure(_, args) => {
-                self.closure_trait_ref_unnormalized(obligation, args, self.tcx().consts.true_)
-            }
+            ty::Closure(..) => self.closure_trait_ref_unnormalized(
+                self_ty,
+                obligation.predicate.def_id(),
+                self.tcx().consts.true_,
+            ),
             ty::CoroutineClosure(_, args) => {
                 args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
                     ty::TraitRef::new(
@@ -896,7 +886,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
         };
 
-        self.confirm_poly_trait_refs(obligation, trait_ref)
+        self.equate_trait_refs(obligation.with(self.tcx(), placeholder_predicate), trait_ref)
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -904,8 +894,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
+
         let tcx = self.tcx();
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
 
         let mut nested = vec![];
         let (trait_ref, kind_ty) = match *self_ty.kind() {
@@ -972,7 +964,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => bug!("expected callable type for AsyncFn candidate"),
         };
 
-        nested.extend(self.confirm_poly_trait_refs(obligation, trait_ref)?);
+        nested.extend(
+            self.equate_trait_refs(obligation.with(tcx, placeholder_predicate), trait_ref)?,
+        );
 
         let goal_kind =
             self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap();
@@ -1025,34 +1019,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// selection of the impl. Therefore, if there is a mismatch, we
     /// report an error to the user.
     #[instrument(skip(self), level = "trace")]
-    fn confirm_poly_trait_refs(
+    fn equate_trait_refs(
         &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
-        self_ty_trait_ref: ty::PolyTraitRef<'tcx>,
+        obligation: TraitObligation<'tcx>,
+        found_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        let obligation_trait_ref =
-            self.infcx.enter_forall_and_leak_universe(obligation.predicate.to_poly_trait_ref());
-        let self_ty_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
+        let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
             HigherRankedType,
-            self_ty_trait_ref,
+            found_trait_ref,
         );
         // Normalize the obligation and expected trait refs together, because why not
-        let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } =
+        let Normalized { obligations: nested, value: (obligation_trait_ref, found_trait_ref) } =
             ensure_sufficient_stack(|| {
                 normalize_with_depth(
                     self,
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
-                    (obligation_trait_ref, self_ty_trait_ref),
+                    (obligation.predicate.trait_ref, found_trait_ref),
                 )
             });
 
         // needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .eq(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
+            .eq(DefineOpaqueTypes::Yes, obligation_trait_ref, found_trait_ref)
             .map(|InferOk { mut obligations, .. }| {
                 obligations.extend(nested);
                 obligations
@@ -1060,7 +1052,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .map_err(|terr| {
                 SignatureMismatch(Box::new(SignatureMismatchData {
                     expected_trait_ref: ty::Binder::dummy(obligation_trait_ref),
-                    found_trait_ref: ty::Binder::dummy(expected_trait_ref),
+                    found_trait_ref: ty::Binder::dummy(found_trait_ref),
                     terr,
                 }))
             })
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 1894fbba302..926044bd6a8 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -60,6 +60,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 mod candidate_assembly;
 mod confirmation;
 
+/// Whether to consider the binder of higher ranked goals for the `leak_check` when
+/// evaluating higher-ranked goals. See #119820 for more info.
+///
+/// While this is a bit hacky, it is necessary to match the behavior of the new solver:
+/// We eagerly instantiate binders in the new solver, outside of candidate selection, so
+/// the leak check inside of candidates does not consider any bound vars from the higher
+/// ranked goal. However, we do exit the binder once we're completely finished with a goal,
+/// so the leak-check can be used in evaluate by causing nested higher-ranked goals to fail.
+#[derive(Debug, Copy, Clone)]
+enum LeakCheckHigherRankedGoal {
+    No,
+    Yes,
+}
+
 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
 pub enum IntercrateAmbiguityCause<'tcx> {
     DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option<Ty<'tcx>> },
@@ -126,8 +140,6 @@ pub struct SelectionContext<'cx, 'tcx> {
     /// policy. In essence, canonicalized queries need their errors propagated
     /// rather than immediately reported because we do not have accurate spans.
     query_mode: TraitQueryMode,
-
-    treat_inductive_cycle: TreatInductiveCycleAs,
 }
 
 // A stack that walks back up the stack frame.
@@ -208,27 +220,6 @@ enum BuiltinImplConditions<'tcx> {
     Ambiguous,
 }
 
-#[derive(Copy, Clone)]
-pub enum TreatInductiveCycleAs {
-    /// This is the previous behavior, where `Recur` represents an inductive
-    /// cycle that is known not to hold. This is not forwards-compatible with
-    /// coinduction, and will be deprecated. This is the default behavior
-    /// of the old trait solver due to back-compat reasons.
-    Recur,
-    /// This is the behavior of the new trait solver, where inductive cycles
-    /// are treated as ambiguous and possibly holding.
-    Ambig,
-}
-
-impl From<TreatInductiveCycleAs> for EvaluationResult {
-    fn from(treat: TreatInductiveCycleAs) -> EvaluationResult {
-        match treat {
-            TreatInductiveCycleAs::Ambig => EvaluatedToAmbigStackDependent,
-            TreatInductiveCycleAs::Recur => EvaluatedToErrStackDependent,
-        }
-    }
-}
-
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
         SelectionContext {
@@ -236,19 +227,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             freshener: infcx.freshener(),
             intercrate_ambiguity_causes: None,
             query_mode: TraitQueryMode::Standard,
-            treat_inductive_cycle: TreatInductiveCycleAs::Recur,
-        }
-    }
-
-    pub fn with_treat_inductive_cycle_as_ambig(
-        infcx: &'cx InferCtxt<'tcx>,
-    ) -> SelectionContext<'cx, 'tcx> {
-        // Should be executed in a context where caching is disabled,
-        // otherwise the cache is poisoned with the temporary result.
-        assert!(infcx.intercrate);
-        SelectionContext {
-            treat_inductive_cycle: TreatInductiveCycleAs::Ambig,
-            ..SelectionContext::new(infcx)
         }
     }
 
@@ -420,7 +398,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     let mut no_candidates_apply = true;
 
                     for c in candidate_set.vec.iter() {
-                        if self.evaluate_candidate(stack, c)?.may_apply() {
+                        if self
+                            .evaluate_candidate(stack, c, LeakCheckHigherRankedGoal::No)?
+                            .may_apply()
+                        {
                             no_candidates_apply = false;
                             break;
                         }
@@ -491,7 +472,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // is needed for specialization. Propagate overflow if it occurs.
         let mut candidates = candidates
             .into_iter()
-            .map(|c| match self.evaluate_candidate(stack, &c) {
+            .map(|c| match self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::No) {
                 Ok(eval) if eval.may_apply() => {
                     Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
                 }
@@ -581,7 +562,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &PredicateObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
         debug_assert!(!self.infcx.next_trait_solver());
-        self.evaluation_probe(|this| {
+        self.evaluation_probe(|this, _outer_universe| {
             let goal =
                 this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
             let mut result = this.evaluate_predicate_recursively(
@@ -597,13 +578,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         })
     }
 
+    /// Computes the evaluation result of `op`, discarding any constraints.
+    ///
+    /// This also runs for leak check to allow higher ranked region errors to impact
+    /// selection. By default it checks for leaks from all universes created inside of
+    /// `op`, but this can be overwritten if necessary.
     fn evaluation_probe(
         &mut self,
-        op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>,
+        op: impl FnOnce(&mut Self, &mut ty::UniverseIndex) -> Result<EvaluationResult, OverflowError>,
     ) -> Result<EvaluationResult, OverflowError> {
         self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
-            let outer_universe = self.infcx.universe();
-            let result = op(self)?;
+            let mut outer_universe = self.infcx.universe();
+            let result = op(self, &mut outer_universe)?;
 
             match self.infcx.leak_check(outer_universe, Some(snapshot)) {
                 Ok(()) => {}
@@ -622,9 +608,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         })
     }
 
-    /// Evaluates the predicates in `predicates` recursively. Note that
-    /// this applies projections in the predicates, and therefore
+    /// Evaluates the predicates in `predicates` recursively. This may
+    /// guide inference. If this is not desired, run it inside of a
     /// is run within an inference probe.
+    /// `probe`.
     #[instrument(skip(self, stack), level = "debug")]
     fn evaluate_predicates_recursively<'o, I>(
         &mut self,
@@ -756,7 +743,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 stack.update_reached_depth(stack_arg.1);
                                 return Ok(EvaluatedToOk);
                             } else {
-                                return Ok(self.treat_inductive_cycle.into());
+                                return Ok(EvaluatedToAmbigStackDependent);
                             }
                         }
                         return Ok(EvaluatedToOk);
@@ -875,7 +862,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             }
                         }
                         ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig),
-                        ProjectAndUnifyResult::Recursive => Ok(self.treat_inductive_cycle.into()),
+                        ProjectAndUnifyResult::Recursive => Ok(EvaluatedToAmbigStackDependent),
                         ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr),
                     }
                 }
@@ -1180,7 +1167,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Some(EvaluatedToOk)
             } else {
                 debug!("evaluate_stack --> recursive, inductive");
-                Some(self.treat_inductive_cycle.into())
+                Some(EvaluatedToAmbigStackDependent)
             }
         } else {
             None
@@ -1230,7 +1217,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         match self.candidate_from_obligation(stack) {
-            Ok(Some(c)) => self.evaluate_candidate(stack, &c),
+            Ok(Some(c)) => self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::Yes),
             Ok(None) => Ok(EvaluatedToAmbig),
             Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
             Err(..) => Ok(EvaluatedToErr),
@@ -1255,6 +1242,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// Further evaluates `candidate` to decide whether all type parameters match and whether nested
     /// obligations are met. Returns whether `candidate` remains viable after this further
     /// scrutiny.
+    ///
+    /// Depending on the value of [LeakCheckHigherRankedGoal], we may ignore the binder of the goal
+    /// when eagerly detecting higher ranked region errors via the `leak_check`. See that enum for
+    /// more info.
     #[instrument(
         level = "debug",
         skip(self, stack),
@@ -1265,10 +1256,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
         candidate: &SelectionCandidate<'tcx>,
+        leak_check_higher_ranked_goal: LeakCheckHigherRankedGoal,
     ) -> Result<EvaluationResult, OverflowError> {
-        let mut result = self.evaluation_probe(|this| {
-            let candidate = (*candidate).clone();
-            match this.confirm_candidate(stack.obligation, candidate) {
+        let mut result = self.evaluation_probe(|this, outer_universe| {
+            // We eagerly instantiate higher ranked goals to prevent universe errors
+            // from impacting candidate selection. This matches the behavior of the new
+            // solver. This slightly weakens type inference.
+            //
+            // In case there are no unresolved type or const variables this
+            // should still not be necessary to select a unique impl as any overlap
+            // relying on a universe error from higher ranked goals should have resulted
+            // in an overlap error in coherence.
+            let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate);
+            let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p));
+            match leak_check_higher_ranked_goal {
+                LeakCheckHigherRankedGoal::No => *outer_universe = self.infcx.universe(),
+                LeakCheckHigherRankedGoal::Yes => {}
+            }
+
+            match this.confirm_candidate(&obligation, candidate.clone()) {
                 Ok(selection) => {
                     debug!(?selection);
                     this.evaluate_predicates_recursively(
@@ -1693,8 +1699,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         stack: &TraitObligationStack<'o, 'tcx>,
         where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        self.evaluation_probe(|this| {
-            match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
+        self.evaluation_probe(|this, outer_universe| {
+            // Eagerly instantiate higher ranked goals.
+            //
+            // See the comment in `evaluate_candidate` to see why.
+            let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate);
+            let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p));
+            *outer_universe = self.infcx.universe();
+            match this.match_where_clause_trait_ref(&obligation, where_clause_trait_ref) {
                 Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations),
                 Err(()) => Ok(EvaluatedToErr),
             }
@@ -2679,26 +2691,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
     #[instrument(skip(self), level = "debug")]
     fn closure_trait_ref_unnormalized(
         &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
-        args: GenericArgsRef<'tcx>,
+        self_ty: Ty<'tcx>,
+        fn_trait_def_id: DefId,
         fn_host_effect: ty::Const<'tcx>,
     ) -> ty::PolyTraitRef<'tcx> {
+        let ty::Closure(_, args) = *self_ty.kind() else {
+            bug!("expected closure, found {self_ty}");
+        };
         let closure_sig = args.as_closure().sig();
 
-        debug!(?closure_sig);
-
-        // NOTE: The self-type is an unboxed closure type and hence is
-        // in fact unparameterized (or at least does not reference any
-        // regions bound in the obligation).
-        let self_ty = obligation
-            .predicate
-            .self_ty()
-            .no_bound_vars()
-            .expect("unboxed closure type should not capture bound vars from the predicate");
-
         closure_trait_ref_and_return_type(
             self.tcx(),
-            obligation.predicate.def_id(),
+            fn_trait_def_id,
             self_ty,
             closure_sig,
             util::TupleArgumentsFlag::No,
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 27dd8f26489..43c750ebbb5 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -239,10 +239,10 @@ fn fulfill_implication<'tcx>(
 
     let source_trait = ImplSubject::Trait(source_trait_ref);
 
-    let selcx = &mut SelectionContext::new(infcx);
+    let selcx = SelectionContext::new(infcx);
     let target_args = infcx.fresh_args_for_item(DUMMY_SP, target_impl);
     let (target_trait, obligations) =
-        util::impl_subject_and_oblig(selcx, param_env, target_impl, target_args, error_cause);
+        util::impl_subject_and_oblig(&selcx, param_env, target_impl, target_args, error_cause);
 
     // do the impls unify? If not, no specialization.
     let Ok(InferOk { obligations: more_obligations, .. }) = infcx
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 1aa65b87f0b..dba014d58b0 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -198,7 +198,7 @@ impl<'tcx> Children {
     }
 }
 
-fn iter_children(children: &mut Children) -> impl Iterator<Item = DefId> + '_ {
+fn iter_children(children: &Children) -> impl Iterator<Item = DefId> + '_ {
     let nonblanket = children.non_blanket_impls.iter().flat_map(|(_, v)| v.iter());
     children.blanket_impls.iter().chain(nonblanket).cloned()
 }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 29d063321a7..d29fc7921bc 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -205,7 +205,7 @@ impl Iterator for SupertraitDefIds<'_> {
 /// returning the resulting subject and all obligations that arise.
 /// The obligations are closed under normalization.
 pub fn impl_subject_and_oblig<'a, 'tcx>(
-    selcx: &mut SelectionContext<'a, 'tcx>,
+    selcx: &SelectionContext<'a, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     impl_def_id: DefId,
     impl_args: GenericArgsRef<'tcx>,
@@ -344,48 +344,6 @@ pub enum TupleArgumentsFlag {
     No,
 }
 
-// Verify that the trait item and its implementation have compatible args lists
-pub fn check_args_compatible<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    assoc_item: ty::AssocItem,
-    args: ty::GenericArgsRef<'tcx>,
-) -> bool {
-    fn check_args_compatible_inner<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        generics: &'tcx ty::Generics,
-        args: &'tcx [ty::GenericArg<'tcx>],
-    ) -> bool {
-        if generics.count() != args.len() {
-            return false;
-        }
-
-        let (parent_args, own_args) = args.split_at(generics.parent_count);
-
-        if let Some(parent) = generics.parent
-            && let parent_generics = tcx.generics_of(parent)
-            && !check_args_compatible_inner(tcx, parent_generics, parent_args)
-        {
-            return false;
-        }
-
-        for (param, arg) in std::iter::zip(&generics.params, own_args) {
-            match (&param.kind, arg.unpack()) {
-                (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
-                | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
-                | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
-                _ => return false,
-            }
-        }
-
-        true
-    }
-
-    let generics = tcx.generics_of(assoc_item.def_id);
-    // Chop off any additional args (RPITIT) args
-    let args = &args[0..generics.count().min(args.len())];
-    check_args_compatible_inner(tcx, generics, args)
-}
-
 /// Executes `f` on `value` after replacing all escaping bound variables with placeholders
 /// and then replaces these placeholders with the original bound variables in the result.
 ///
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 7941a8fe95c..19ca147d3ad 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
     fn visit_ty(&mut self, t: <TyCtxt<'tcx> as ty::Interner>::Ty) -> Self::Result {
         debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind());
 
+        let tcx = self.tcx();
+
         match *t.kind() {
             ty::Bool
             | ty::Char
@@ -707,6 +709,16 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
             }
 
             ty::FnDef(did, args) => {
+                // HACK: Check the return type of function definitions for
+                // well-formedness to mostly fix #84533. This is still not
+                // perfect and there may be ways to abuse the fact that we
+                // ignore requirements with escaping bound vars. That's a
+                // more general issue however.
+                //
+                // FIXME(eddyb) add the type to `walker` instead of recursing.
+                let fn_sig = tcx.fn_sig(did).instantiate(tcx, args);
+                fn_sig.output().skip_binder().visit_with(self);
+
                 let obligations = self.nominal_obligations(did, args);
                 self.out.extend(obligations);
             }
@@ -716,7 +728,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
                     let cause = self.cause(traits::ReferenceOutlivesReferent(t));
                     self.out.push(traits::Obligation::with_depth(
-                        self.tcx(),
+                        tcx,
                         cause,
                         self.recursion_depth,
                         self.param_env,
@@ -805,12 +817,12 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 // obligations that don't refer to Self and
                 // checking those
 
-                let defer_to_coercion = self.tcx().features().object_safe_for_dispatch;
+                let defer_to_coercion = tcx.features().object_safe_for_dispatch;
 
                 if !defer_to_coercion {
                     if let Some(principal) = data.principal_def_id() {
                         self.out.push(traits::Obligation::with_depth(
-                            self.tcx(),
+                            tcx,
                             self.cause(traits::WellFormed(None)),
                             self.recursion_depth,
                             self.param_env,
@@ -835,7 +847,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
             ty::Infer(_) => {
                 let cause = self.cause(traits::WellFormed(None));
                 self.out.push(traits::Obligation::with_depth(
-                    self.tcx(),
+                    tcx,
                     cause,
                     self.recursion_depth,
                     self.param_env,
@@ -850,6 +862,8 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
     }
 
     fn visit_const(&mut self, c: <TyCtxt<'tcx> as ty::Interner>::Const) -> Self::Result {
+        let tcx = self.tcx();
+
         match c.kind() {
             ty::ConstKind::Unevaluated(uv) => {
                 if !c.has_escaping_bound_vars() {
@@ -861,7 +875,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                     ));
                     let cause = self.cause(traits::WellFormed(None));
                     self.out.push(traits::Obligation::with_depth(
-                        self.tcx(),
+                        tcx,
                         cause,
                         self.recursion_depth,
                         self.param_env,
@@ -873,7 +887,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 let cause = self.cause(traits::WellFormed(None));
 
                 self.out.push(traits::Obligation::with_depth(
-                    self.tcx(),
+                    tcx,
                     cause,
                     self.recursion_depth,
                     self.param_env,
@@ -895,7 +909,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 ));
                 let cause = self.cause(traits::WellFormed(None));
                 self.out.push(traits::Obligation::with_depth(
-                    self.tcx(),
+                    tcx,
                     cause,
                     self.recursion_depth,
                     self.param_env,
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 2a2e53a81ed..acbcc3918b2 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -82,7 +82,7 @@ fn check_binop(op: mir::BinOp) -> bool {
     match op {
         Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
         | BitAnd | BitOr | Shl | ShlUnchecked | Shr | ShrUnchecked | Eq | Lt | Le | Ne | Ge
-        | Gt => true,
+        | Gt | Cmp => true,
         Offset => false,
     }
 }
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 331970ac362..4ecb0ea7cd9 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -8,7 +8,9 @@ use rustc_middle::ty::layout::{
     IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, AdtDef, EarlyBinder, FieldDef, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt,
+};
 use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
@@ -377,7 +379,7 @@ fn layout_of_uncached<'tcx>(
             }
 
             // Type of the first ADT field:
-            let f0_ty = fields[FieldIdx::from_u32(0)].ty(tcx, args);
+            let f0_ty = fields[FieldIdx::ZERO].ty(tcx, args);
 
             // Heterogeneous SIMD vectors are not supported:
             // (should be caught by typeck)
@@ -506,6 +508,40 @@ fn layout_of_uncached<'tcx>(
                 ));
             }
 
+            let err_if_unsized = |field: &FieldDef, err_msg: &str| {
+                let field_ty = tcx.type_of(field.did);
+                let is_unsized = tcx
+                    .try_instantiate_and_normalize_erasing_regions(args, cx.param_env, field_ty)
+                    .map(|f| !f.is_sized(tcx, cx.param_env))
+                    .map_err(|e| {
+                        error(
+                            cx,
+                            LayoutError::NormalizationFailure(field_ty.instantiate_identity(), e),
+                        )
+                    })?;
+
+                if is_unsized {
+                    cx.tcx.dcx().span_delayed_bug(tcx.def_span(def.did()), err_msg.to_owned());
+                    Err(error(cx, LayoutError::Unknown(ty)))
+                } else {
+                    Ok(())
+                }
+            };
+
+            if def.is_struct() {
+                if let Some((_, fields_except_last)) =
+                    def.non_enum_variant().fields.raw.split_last()
+                {
+                    for f in fields_except_last {
+                        err_if_unsized(f, "only the last field of a struct can be unsized")?;
+                    }
+                }
+            } else {
+                for f in def.all_fields() {
+                    err_if_unsized(f, &format!("{}s cannot have unsized fields", def.descr()))?;
+                }
+            }
+
             let get_discriminant_type =
                 |min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max);
 
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index fc16edc6d13..a652bb78116 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -7,7 +7,6 @@ use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_span::Span;
-use rustc_trait_selection::traits::check_args_compatible;
 
 use crate::errors::{DuplicateArg, NotParam};
 
@@ -250,7 +249,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
                                 ty::GenericArgs::identity_for_item(self.tcx, parent),
                             );
 
-                            if check_args_compatible(self.tcx, assoc, impl_args) {
+                            if self.tcx.check_args_compatible(assoc.def_id, impl_args) {
                                 self.tcx
                                     .type_of(assoc.def_id)
                                     .instantiate(self.tcx, impl_args)
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
index 8d402588398..01bb3d73dbd 100644
--- a/compiler/rustc_type_ir/src/fold.rs
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -136,31 +136,21 @@ pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Never> {
         t.super_fold_with(self)
     }
 
-    fn fold_ty(&mut self, t: I::Ty) -> I::Ty
-    where
-        I::Ty: TypeSuperFoldable<I>,
-    {
+    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
         t.super_fold_with(self)
     }
 
     // The default region folder is a no-op because `Region` is non-recursive
-    // and has no `super_fold_with` method to call. That also explains the
-    // lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
+    // and has no `super_fold_with` method to call.
     fn fold_region(&mut self, r: I::Region) -> I::Region {
         r
     }
 
-    fn fold_const(&mut self, c: I::Const) -> I::Const
-    where
-        I::Const: TypeSuperFoldable<I>,
-    {
+    fn fold_const(&mut self, c: I::Const) -> I::Const {
         c.super_fold_with(self)
     }
 
-    fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate
-    where
-        I::Predicate: TypeSuperFoldable<I>,
-    {
+    fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
         p.super_fold_with(self)
     }
 }
@@ -185,31 +175,21 @@ pub trait FallibleTypeFolder<I: Interner>: Sized {
         t.try_super_fold_with(self)
     }
 
-    fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error>
-    where
-        I::Ty: TypeSuperFoldable<I>,
-    {
+    fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error> {
         t.try_super_fold_with(self)
     }
 
     // The default region folder is a no-op because `Region` is non-recursive
-    // and has no `super_fold_with` method to call. That also explains the
-    // lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
+    // and has no `super_fold_with` method to call.
     fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> {
         Ok(r)
     }
 
-    fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error>
-    where
-        I::Const: TypeSuperFoldable<I>,
-    {
+    fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error> {
         c.try_super_fold_with(self)
     }
 
-    fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error>
-    where
-        I::Predicate: TypeSuperFoldable<I>,
-    {
+    fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error> {
         p.try_super_fold_with(self)
     }
 }
@@ -234,10 +214,7 @@ where
         Ok(self.fold_binder(t))
     }
 
-    fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Never>
-    where
-        I::Ty: TypeSuperFoldable<I>,
-    {
+    fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Never> {
         Ok(self.fold_ty(t))
     }
 
@@ -245,17 +222,11 @@ where
         Ok(self.fold_region(r))
     }
 
-    fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Never>
-    where
-        I::Const: TypeSuperFoldable<I>,
-    {
+    fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Never> {
         Ok(self.fold_const(c))
     }
 
-    fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Never>
-    where
-        I::Predicate: TypeSuperFoldable<I>,
-    {
+    fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Never> {
         Ok(self.fold_predicate(p))
     }
 }
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index ae1e1902f14..7a2885dd3bb 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -2,13 +2,14 @@ use smallvec::SmallVec;
 use std::fmt::Debug;
 use std::hash::Hash;
 
+use crate::fold::TypeSuperFoldable;
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{
     new, BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebugWithInfcx, RegionKind, TyKind,
     UniverseIndex,
 };
 
-pub trait Interner: Sized {
+pub trait Interner: Sized + Copy {
     type DefId: Copy + Debug + Hash + Eq;
     type AdtDef: Copy + Debug + Hash + Eq;
 
@@ -34,6 +35,7 @@ pub trait Interner: Sized {
         + Into<Self::GenericArg>
         + IntoKind<Kind = TyKind<Self>>
         + TypeSuperVisitable<Self>
+        + TypeSuperFoldable<Self>
         + Flags
         + new::Ty<Self>;
     type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
@@ -57,6 +59,7 @@ pub trait Interner: Sized {
         + IntoKind<Kind = ConstKind<Self>>
         + ConstTy<Self>
         + TypeSuperVisitable<Self>
+        + TypeSuperFoldable<Self>
         + Flags
         + new::Const<Self>;
     type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
@@ -82,7 +85,13 @@ pub trait Interner: Sized {
     type PlaceholderRegion: Copy + Debug + Hash + Eq + PlaceholderLike;
 
     // Predicates
-    type Predicate: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
+    type Predicate: Copy
+        + Debug
+        + Hash
+        + Eq
+        + TypeSuperVisitable<Self>
+        + TypeSuperFoldable<Self>
+        + Flags;
     type TraitPredicate: Copy + Debug + Hash + Eq;
     type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
     type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index c01baa58ae7..45e22b12a8b 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -314,7 +314,7 @@ rustc_index::newtype_index! {
 }
 
 impl UniverseIndex {
-    pub const ROOT: UniverseIndex = UniverseIndex::from_u32(0);
+    pub const ROOT: UniverseIndex = UniverseIndex::ZERO;
 
     /// Returns the "next" universe index in order -- this new index
     /// is considered to extend all previous universes. This
diff --git a/compiler/rustc_type_ir/src/new.rs b/compiler/rustc_type_ir/src/new.rs
index e7e695e5908..1572a641d06 100644
--- a/compiler/rustc_type_ir/src/new.rs
+++ b/compiler/rustc_type_ir/src/new.rs
@@ -6,6 +6,8 @@ pub trait Ty<I: Interner<Ty = Self>> {
 
 pub trait Region<I: Interner<Region = Self>> {
     fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
+
+    fn new_static(interner: I) -> Self;
 }
 
 pub trait Const<I: Interner<Const = Self>> {
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index 7c536a3e914..8f77a19fc0e 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -329,6 +329,7 @@ pub enum BinOp {
     Ne,
     Ge,
     Gt,
+    Cmp,
     Offset,
 }
 
@@ -368,6 +369,9 @@ impl BinOp {
                 assert!(lhs_kind.is_primitive() || lhs_kind.is_raw_ptr() || lhs_kind.is_fn_ptr());
                 Ty::bool_ty()
             }
+            BinOp::Cmp => {
+                unimplemented!("Should cmp::Ordering be a RigidTy?");
+            }
         }
     }
 }
@@ -967,8 +971,9 @@ pub enum PointerCoercion {
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum CastKind {
+    // FIXME(smir-rename): rename this to PointerExposeProvenance
     PointerExposeAddress,
-    PointerFromExposedAddress,
+    PointerWithExposedProvenance,
     PointerCoercion(PointerCoercion),
     DynStar,
     IntToInt,
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 21db222095f..3e8d186b97e 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -654,7 +654,7 @@ impl AdtDef {
         with(|cx| cx.def_ty(self.0))
     }
 
-    /// Retrieve the type of this Adt instantiating the type with the given arguments.
+    /// Retrieve the type of this Adt by instantiating and normalizing it with the given arguments.
     ///
     /// This will assume the type can be instantiated with these arguments.
     pub fn ty_with_args(&self, args: &GenericArgs) -> Ty {
@@ -733,7 +733,7 @@ pub struct FieldDef {
 }
 
 impl FieldDef {
-    /// Retrieve the type of this field instantiating the type with the given arguments.
+    /// Retrieve the type of this field instantiating and normalizing it with the given arguments.
     ///
     /// This will assume the type can be instantiated with these arguments.
     pub fn ty_with_args(&self, args: &GenericArgs) -> Ty {
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 41adc2e79dc..e2fc320f280 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -2087,7 +2087,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
         // buffer without it being full emerge
         debug_assert!(self.is_full());
         let old_cap = self.capacity();
-        self.buf.reserve_for_push(old_cap);
+        self.buf.grow_one();
         unsafe {
             self.handle_capacity_increase(old_cap);
         }
@@ -2464,8 +2464,10 @@ impl<T, A: Allocator> VecDeque<T, A> {
     ///
     /// let mut deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
     /// let num = 42;
-    /// let idx = deque.partition_point(|&x| x < num);
-    /// // The above is equivalent to `let idx = deque.binary_search(&num).unwrap_or_else(|x| x);`
+    /// let idx = deque.partition_point(|&x| x <= num);
+    /// // If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to
+    /// // `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` may allow `insert`
+    /// // to shift less elements.
     /// deque.insert(idx, num);
     /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
     /// ```
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 26d238154a3..cafd59cb0d9 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -166,7 +166,6 @@
 #![feature(try_trait_v2)]
 #![feature(try_with_capacity)]
 #![feature(tuple_trait)]
-#![feature(unchecked_math)]
 #![feature(unicode_internals)]
 #![feature(unsize)]
 #![feature(utf8_chunks)]
@@ -199,7 +198,6 @@
 #![feature(multiple_supertrait_upcastable)]
 #![feature(negative_impls)]
 #![feature(never_type)]
-#![feature(pointer_is_aligned)]
 #![feature(rustc_allow_const_fn_unstable)]
 #![feature(rustc_attrs)]
 #![feature(slice_internals)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 175e23b543c..0883080d735 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -345,12 +345,12 @@ impl<T, A: Allocator> RawVec<T, A> {
         }
     }
 
-    /// A specialized version of `reserve()` used only by the hot and
-    /// oft-instantiated `Vec::push()`, which does its own capacity check.
+    /// A specialized version of `self.reserve(len, 1)` which requires the
+    /// caller to ensure `len == self.capacity()`.
     #[cfg(not(no_global_oom_handling))]
     #[inline(never)]
-    pub fn reserve_for_push(&mut self, len: usize) {
-        if let Err(err) = self.grow_amortized(len, 1) {
+    pub fn grow_one(&mut self) {
+        if let Err(err) = self.grow_amortized(self.cap.0, 1) {
             handle_error(err);
         }
     }
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 7464df268cc..5d552c8f15c 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -72,9 +72,9 @@ use crate::vec::Vec;
 
 /// A UTF-8–encoded, growable string.
 ///
-/// The `String` type is the most common string type that has ownership over the
-/// contents of the string. It has a close relationship with its borrowed
-/// counterpart, the primitive [`str`].
+/// `String` is the most common string type. It has ownership over the contents
+/// of the string, stored in a heap-allocated buffer (see [Representation](#representation)).
+/// It is closely related to its borrowed counterpart, the primitive [`str`].
 ///
 /// # Examples
 ///
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 8ca8046dac5..7e3463bc082 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1547,7 +1547,7 @@ impl<T, A: Allocator> Vec<T, A> {
 
         // space for the new element
         if len == self.buf.capacity() {
-            self.reserve(1);
+            self.buf.grow_one();
         }
 
         unsafe {
@@ -1967,7 +1967,7 @@ impl<T, A: Allocator> Vec<T, A> {
         // This will panic or abort if we would allocate > isize::MAX bytes
         // or if the length increment would overflow for zero-sized types.
         if self.len == self.buf.capacity() {
-            self.buf.reserve_for_push(self.len);
+            self.buf.grow_one();
         }
         unsafe {
             let end = self.as_mut_ptr().add(self.len);
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 04709af5c0a..a34bce66496 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -37,7 +37,7 @@
 #![feature(const_trait_impl)]
 #![feature(const_str_from_utf8)]
 #![feature(panic_update_hook)]
-#![feature(pointer_is_aligned)]
+#![feature(pointer_is_aligned_to)]
 #![feature(slice_flatten)]
 #![feature(thin_box)]
 #![feature(strict_provenance)]
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index a4252d0c9e0..37cb8e7d303 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -40,10 +40,10 @@
 //!
 //! ## Examples
 //!
-//! Consider a situation where we want to log out a value passed to a function.
-//! We know the value we're working on implements Debug, but we don't know its
+//! Consider a situation where we want to log a value passed to a function.
+//! We know the value we're working on implements `Debug`, but we don't know its
 //! concrete type. We want to give special treatment to certain types: in this
-//! case printing out the length of String values prior to their value.
+//! case printing out the length of `String` values prior to their value.
 //! We don't know the concrete type of our value at compile time, so we need to
 //! use runtime reflection instead.
 //!
@@ -51,7 +51,7 @@
 //! use std::fmt::Debug;
 //! use std::any::Any;
 //!
-//! // Logger function for any type that implements Debug.
+//! // Logger function for any type that implements `Debug`.
 //! fn log<T: Any + Debug>(value: &T) {
 //!     let value_any = value as &dyn Any;
 //!
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index ba86334f950..44ae72bcd26 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -231,6 +231,9 @@ mod impls {
         bool char
     }
 
+    #[cfg(not(bootstrap))]
+    impl_clone! { f16 f128 }
+
     #[unstable(feature = "never_type", issue = "35121")]
     impl Clone for ! {
         #[inline]
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index a2f07814726..81bba927554 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -376,6 +376,10 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
 /// ```
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
+// This is a lang item only so that `BinOp::Cmp` in MIR can return it.
+// It has no special behaviour, but does require that the three variants
+// `Less`/`Equal`/`Greater` remain `-1_i8`/`0_i8`/`+1_i8` respectively.
+#[cfg_attr(not(bootstrap), lang = "Ordering")]
 #[repr(i8)]
 pub enum Ordering {
     /// An ordering where a compared value is less than another.
@@ -848,6 +852,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
     #[stable(feature = "ord_max_min", since = "1.21.0")]
     #[inline]
     #[must_use]
+    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_ord_max")]
     fn max(self, other: Self) -> Self
     where
         Self: Sized,
@@ -868,6 +873,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
     #[stable(feature = "ord_max_min", since = "1.21.0")]
     #[inline]
     #[must_use]
+    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_ord_min")]
     fn min(self, other: Self) -> Self
     where
         Self: Sized,
@@ -1154,6 +1160,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialord_cmp")]
     fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
 
     /// This method tests less than (for `self` and `other`) and is used by the `<` operator.
@@ -1168,6 +1175,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialord_lt")]
     fn lt(&self, other: &Rhs) -> bool {
         matches!(self.partial_cmp(other), Some(Less))
     }
@@ -1185,6 +1193,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialord_le")]
     fn le(&self, other: &Rhs) -> bool {
         matches!(self.partial_cmp(other), Some(Less | Equal))
     }
@@ -1201,6 +1210,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialord_gt")]
     fn gt(&self, other: &Rhs) -> bool {
         matches!(self.partial_cmp(other), Some(Greater))
     }
@@ -1218,6 +1228,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialord_ge")]
     fn ge(&self, other: &Rhs) -> bool {
         matches!(self.partial_cmp(other), Some(Greater | Equal))
     }
@@ -1489,6 +1500,9 @@ mod impls {
         bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64
     }
 
+    #[cfg(not(bootstrap))]
+    partial_eq_impl! { f16 f128 }
+
     macro_rules! eq_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
@@ -1541,13 +1555,23 @@ mod impls {
 
     partial_ord_impl! { f32 f64 }
 
+    #[cfg(not(bootstrap))]
+    partial_ord_impl! { f16 f128 }
+
     macro_rules! ord_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
             impl PartialOrd for $t {
                 #[inline]
                 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
-                    Some(self.cmp(other))
+                    #[cfg(bootstrap)]
+                    {
+                        Some(self.cmp(other))
+                    }
+                    #[cfg(not(bootstrap))]
+                    {
+                        Some(crate::intrinsics::three_way_compare(*self, *other))
+                    }
                 }
                 #[inline(always)]
                 fn lt(&self, other: &$t) -> bool { (*self) < (*other) }
@@ -1563,11 +1587,18 @@ mod impls {
             impl Ord for $t {
                 #[inline]
                 fn cmp(&self, other: &$t) -> Ordering {
-                    // The order here is important to generate more optimal assembly.
-                    // See <https://github.com/rust-lang/rust/issues/63758> for more info.
-                    if *self < *other { Less }
-                    else if *self == *other { Equal }
-                    else { Greater }
+                    #[cfg(bootstrap)]
+                    {
+                        // The order here is important to generate more optimal assembly.
+                        // See <https://github.com/rust-lang/rust/issues/63758> for more info.
+                        if *self < *other { Less }
+                        else if *self == *other { Equal }
+                        else { Greater }
+                    }
+                    #[cfg(not(bootstrap))]
+                    {
+                        crate::intrinsics::three_way_compare(*self, *other)
+                    }
                 }
             }
         )*)
diff --git a/library/core/src/default.rs b/library/core/src/default.rs
index a5075554682..e717a8d022f 100644
--- a/library/core/src/default.rs
+++ b/library/core/src/default.rs
@@ -178,5 +178,9 @@ default_impl! { i32, 0, "Returns the default value of `0`" }
 default_impl! { i64, 0, "Returns the default value of `0`" }
 default_impl! { i128, 0, "Returns the default value of `0`" }
 
+#[cfg(not(bootstrap))]
+default_impl! { f16, 0.0f16, "Returns the default value of `0.0`" }
 default_impl! { f32, 0.0f32, "Returns the default value of `0.0`" }
 default_impl! { f64, 0.0f64, "Returns the default value of `0.0`" }
+#[cfg(not(bootstrap))]
+default_impl! { f128, 0.0f128, "Returns the default value of `0.0`" }
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index e880d5758ec..287f6c23c89 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -2438,8 +2438,8 @@ impl Display for char {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Pointer for *const T {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
-        // Cast is needed here because `.expose_addr()` requires `T: Sized`.
-        pointer_fmt_inner((*self as *const ()).expose_addr(), f)
+        // Cast is needed here because `.expose_provenance()` requires `T: Sized`.
+        pointer_fmt_inner((*self as *const ()).expose_provenance(), f)
     }
 }
 
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index ef0793a3e46..1c93a7b28fd 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -752,6 +752,18 @@ pub trait BuildHasher {
 #[stable(since = "1.7.0", feature = "build_hasher")]
 pub struct BuildHasherDefault<H>(marker::PhantomData<fn() -> H>);
 
+impl<H> BuildHasherDefault<H> {
+    /// Creates a new BuildHasherDefault for Hasher `H`.
+    #[unstable(
+        feature = "build_hasher_default_const_new",
+        issue = "123197",
+        reason = "recently added"
+    )]
+    pub const fn new() -> Self {
+        BuildHasherDefault(marker::PhantomData)
+    }
+}
+
 #[stable(since = "1.9.0", feature = "core_impl_debug")]
 impl<H> fmt::Debug for BuildHasherDefault<H> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -778,7 +790,7 @@ impl<H> Clone for BuildHasherDefault<H> {
 #[stable(since = "1.7.0", feature = "build_hasher")]
 impl<H> Default for BuildHasherDefault<H> {
     fn default() -> BuildHasherDefault<H> {
-        BuildHasherDefault(marker::PhantomData)
+        Self::new()
     }
 }
 
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index ae6e39d19e1..b09d9fab8a7 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2146,6 +2146,18 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn bitreverse<T: Copy>(x: T) -> T;
 
+    /// Does a three-way comparison between the two integer arguments.
+    ///
+    /// This is included as an intrinsic as it's useful to let it be one thing
+    /// in MIR, rather than the multiple checks and switches that make its IR
+    /// large and difficult to optimize.
+    ///
+    /// The stabilized version of this intrinsic is [`Ord::cmp`].
+    #[cfg(not(bootstrap))]
+    #[rustc_const_unstable(feature = "const_three_way_compare", issue = "none")]
+    #[rustc_safe_intrinsic]
+    pub fn three_way_compare<T: Copy>(lhs: T, rhs: T) -> crate::cmp::Ordering;
+
     /// Performs checked integer addition.
     ///
     /// Note that, unlike most intrinsics, this is safe to call;
@@ -2224,40 +2236,45 @@ extern "rust-intrinsic" {
     /// Safe wrappers for this intrinsic are available on the integer
     /// primitives via the `checked_shl` method. For example,
     /// [`u32::checked_shl`]
+    #[cfg(not(bootstrap))]
     #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
     #[rustc_nounwind]
-    pub fn unchecked_shl<T: Copy>(x: T, y: T) -> T;
+    pub fn unchecked_shl<T: Copy, U: Copy>(x: T, y: U) -> T;
     /// Performs an unchecked right shift, resulting in undefined behavior when
     /// `y < 0` or `y >= N`, where N is the width of T in bits.
     ///
     /// Safe wrappers for this intrinsic are available on the integer
     /// primitives via the `checked_shr` method. For example,
     /// [`u32::checked_shr`]
+    #[cfg(not(bootstrap))]
     #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
     #[rustc_nounwind]
-    pub fn unchecked_shr<T: Copy>(x: T, y: T) -> T;
+    pub fn unchecked_shr<T: Copy, U: Copy>(x: T, y: U) -> T;
 
     /// Returns the result of an unchecked addition, resulting in
     /// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`.
     ///
-    /// This intrinsic does not have a stable counterpart.
-    #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")]
+    /// The stable counterpart of this intrinsic is `unchecked_add` on the various
+    /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`].
+    #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_nounwind]
     pub fn unchecked_add<T: Copy>(x: T, y: T) -> T;
 
     /// Returns the result of an unchecked subtraction, resulting in
     /// undefined behavior when `x - y > T::MAX` or `x - y < T::MIN`.
     ///
-    /// This intrinsic does not have a stable counterpart.
-    #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")]
+    /// The stable counterpart of this intrinsic is `unchecked_sub` on the various
+    /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`].
+    #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_nounwind]
     pub fn unchecked_sub<T: Copy>(x: T, y: T) -> T;
 
     /// Returns the result of an unchecked multiplication, resulting in
     /// undefined behavior when `x * y > T::MAX` or `x * y < T::MIN`.
     ///
-    /// This intrinsic does not have a stable counterpart.
-    #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")]
+    /// The stable counterpart of this intrinsic is `unchecked_mul` on the various
+    /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`].
+    #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_nounwind]
     pub fn unchecked_mul<T: Copy>(x: T, y: T) -> T;
 
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index 427a95f4665..eeff4ec609a 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -540,6 +540,10 @@ extern "rust-intrinsic" {
     /// `T` must be a vector of pointers.
     ///
     /// `U` must be a vector of `usize` with the same length as `T`.
+    #[cfg(not(bootstrap))]
+    #[rustc_nounwind]
+    pub fn simd_expose_provenance<T, U>(ptr: T) -> U;
+    #[cfg(bootstrap)]
     #[rustc_nounwind]
     pub fn simd_expose_addr<T, U>(ptr: T) -> U;
 
@@ -549,6 +553,10 @@ extern "rust-intrinsic" {
     ///
     /// `U` must be a vector of pointers, with the same length as `T`.
     #[rustc_nounwind]
+    #[cfg(not(bootstrap))]
+    pub fn simd_with_exposed_provenance<T, U>(addr: T) -> U;
+    #[rustc_nounwind]
+    #[cfg(bootstrap)]
     pub fn simd_from_exposed_addr<T, U>(addr: T) -> U;
 
     /// Swap bytes of each element.
@@ -655,3 +663,8 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn simd_flog<T>(a: T) -> T;
 }
+
+#[cfg(bootstrap)]
+pub use simd_expose_addr as simd_expose_provenance;
+#[cfg(bootstrap)]
+pub use simd_from_exposed_addr as simd_with_exposed_provenance;
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index cf13496b367..ba19ca1f45d 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -137,7 +137,7 @@
 #![feature(const_heap)]
 #![feature(const_hint_assert_unchecked)]
 #![feature(const_index_range_slice_index)]
-#![feature(const_int_unchecked_arith)]
+#![feature(const_int_from_str)]
 #![feature(const_intrinsic_copy)]
 #![feature(const_intrinsic_forget)]
 #![feature(const_ipv4)]
@@ -197,7 +197,6 @@
 #![feature(str_split_inclusive_remainder)]
 #![feature(str_split_remainder)]
 #![feature(strict_provenance)]
-#![feature(unchecked_math)]
 #![feature(unchecked_shifts)]
 #![feature(utf16_extra)]
 #![feature(utf16_extra_const)]
@@ -206,6 +205,8 @@
 //
 // Language features:
 // tidy-alphabetical-start
+#![cfg_attr(not(bootstrap), feature(f128))]
+#![cfg_attr(not(bootstrap), feature(f16))]
 #![feature(abi_unadjusted)]
 #![feature(adt_const_params)]
 #![feature(allow_internal_unsafe)]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 574a357b44a..6da05a1ca86 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1053,7 +1053,8 @@ pub(crate) mod builtin {
     ///
     /// If the environment variable is not defined, then a compilation error
     /// will be emitted. To not emit a compile error, use the [`option_env!`]
-    /// macro instead.
+    /// macro instead. A compilation error will also be emitted if the
+    /// environment variable is not a vaild Unicode string.
     ///
     /// # Examples
     ///
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index a56a2578c22..fb97b3bfa09 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -426,7 +426,13 @@ marker_impls! {
         bool, char,
         {T: ?Sized} *const T,
         {T: ?Sized} *mut T,
+}
 
+#[cfg(not(bootstrap))]
+marker_impls! {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    Copy for
+        f16, f128,
 }
 
 #[unstable(feature = "never_type", issue = "35121")]
@@ -817,6 +823,13 @@ pub trait DiscriminantKind {
 /// This can be used to declare that a constant with a generic type
 /// will not contain interior mutability, and subsequently allow
 /// placing the constant behind references.
+///
+/// # Safety
+///
+/// This trait is a core part of the language, it is just expressed as a trait in libcore for
+/// convenience. Do *not* implement it for other types.
+// FIXME: Eventually this trait should become `#[rustc_deny_explicit_impl]`.
+// That requires porting the impls below to native internal impls.
 #[lang = "freeze"]
 #[unstable(feature = "freeze", issue = "121675")]
 pub unsafe auto trait Freeze {}
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index 14e99578a7c..a2d7e6f7b07 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -113,8 +113,9 @@ pub enum IntErrorKind {
 impl ParseIntError {
     /// Outputs the detailed cause of parsing an integer failing.
     #[must_use]
+    #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")]
     #[stable(feature = "int_error_matching", since = "1.55.0")]
-    pub fn kind(&self) -> &IntErrorKind {
+    pub const fn kind(&self) -> &IntErrorKind {
         &self.kind
     }
 }
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index fa37ee4ffb2..e34e9b7fff6 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -60,32 +60,6 @@ macro_rules! int_impl {
         #[stable(feature = "int_bits_const", since = "1.53.0")]
         pub const BITS: u32 = <$UnsignedT>::BITS;
 
-        /// Converts a string slice in a given base to an integer.
-        ///
-        /// The string is expected to be an optional `+` or `-` sign followed by digits.
-        /// Leading and trailing whitespace represent an error. Digits are a subset of these characters,
-        /// depending on `radix`:
-        ///
-        ///  * `0-9`
-        ///  * `a-z`
-        ///  * `A-Z`
-        ///
-        /// # Panics
-        ///
-        /// This function panics if `radix` is not in the range from 2 to 36.
-        ///
-        /// # Examples
-        ///
-        /// Basic usage:
-        ///
-        /// ```
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")]
-        /// ```
-        #[stable(feature = "rust1", since = "1.0.0")]
-        pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
-            from_str_radix(src, radix)
-        }
-
         /// Returns the number of ones in the binary representation of `self`.
         ///
         /// # Examples
@@ -492,21 +466,25 @@ macro_rules! int_impl {
         /// Unchecked integer addition. Computes `self + rhs`, assuming overflow
         /// cannot occur.
         ///
+        /// Calling `x.unchecked_add(y)` is semantically equivalent to calling
+        /// `x.`[`checked_add`]`(y).`[`unwrap_unchecked`]`()`.
+        ///
+        /// If you're just trying to avoid the panic in debug mode, then **do not**
+        /// use this.  Instead, you're looking for [`wrapping_add`].
+        ///
         /// # Safety
         ///
         /// This results in undefined behavior when
         #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")]
         /// i.e. when [`checked_add`] would return `None`.
         ///
+        /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked
         #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")]
-        #[unstable(
-            feature = "unchecked_math",
-            reason = "niche optimization path",
-            issue = "85122",
-        )]
+        #[doc = concat!("[`wrapping_add`]: ", stringify!($SelfT), "::wrapping_add")]
+        #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_const_unstable(feature = "unchecked_math", issue = "85122")]
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
@@ -630,21 +608,25 @@ macro_rules! int_impl {
         /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
         /// cannot occur.
         ///
+        /// Calling `x.unchecked_sub(y)` is semantically equivalent to calling
+        /// `x.`[`checked_sub`]`(y).`[`unwrap_unchecked`]`()`.
+        ///
+        /// If you're just trying to avoid the panic in debug mode, then **do not**
+        /// use this.  Instead, you're looking for [`wrapping_sub`].
+        ///
         /// # Safety
         ///
         /// This results in undefined behavior when
         #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")]
         /// i.e. when [`checked_sub`] would return `None`.
         ///
+        /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked
         #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")]
-        #[unstable(
-            feature = "unchecked_math",
-            reason = "niche optimization path",
-            issue = "85122",
-        )]
+        #[doc = concat!("[`wrapping_sub`]: ", stringify!($SelfT), "::wrapping_sub")]
+        #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_const_unstable(feature = "unchecked_math", issue = "85122")]
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
@@ -768,21 +750,25 @@ macro_rules! int_impl {
         /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
         /// cannot occur.
         ///
+        /// Calling `x.unchecked_mul(y)` is semantically equivalent to calling
+        /// `x.`[`checked_mul`]`(y).`[`unwrap_unchecked`]`()`.
+        ///
+        /// If you're just trying to avoid the panic in debug mode, then **do not**
+        /// use this.  Instead, you're looking for [`wrapping_mul`].
+        ///
         /// # Safety
         ///
         /// This results in undefined behavior when
         #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")]
         /// i.e. when [`checked_mul`] would return `None`.
         ///
+        /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked
         #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")]
-        #[unstable(
-            feature = "unchecked_math",
-            reason = "niche optimization path",
-            issue = "85122",
-        )]
+        #[doc = concat!("[`wrapping_mul`]: ", stringify!($SelfT), "::wrapping_mul")]
+        #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_const_unstable(feature = "unchecked_math", issue = "85122")]
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
@@ -1241,10 +1227,18 @@ macro_rules! int_impl {
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
-            // SAFETY: the caller must uphold the safety contract for
-            // `unchecked_shl`.
-            // Any legal shift amount is losslessly representable in the self type.
-            unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
+            #[cfg(bootstrap)]
+            {
+                // For bootstrapping, just use built-in primitive shift.
+                // panicking is a legal manifestation of UB
+                self << rhs
+            }
+            #[cfg(not(bootstrap))]
+            {
+                // SAFETY: the caller must uphold the safety contract for
+                // `unchecked_shl`.
+                unsafe { intrinsics::unchecked_shl(self, rhs) }
+            }
         }
 
         /// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
@@ -1324,10 +1318,18 @@ macro_rules! int_impl {
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
-            // SAFETY: the caller must uphold the safety contract for
-            // `unchecked_shr`.
-            // Any legal shift amount is losslessly representable in the self type.
-            unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
+            #[cfg(bootstrap)]
+            {
+                // For bootstrapping, just use built-in primitive shift.
+                // panicking is a legal manifestation of UB
+                self >> rhs
+            }
+            #[cfg(not(bootstrap))]
+            {
+                // SAFETY: the caller must uphold the safety contract for
+                // `unchecked_shr`.
+                unsafe { intrinsics::unchecked_shr(self, rhs) }
+            }
         }
 
         /// Checked absolute value. Computes `self.abs()`, returning `None` if
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 03c977abbbb..9ebbb4ffe80 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -6,7 +6,6 @@ use crate::ascii;
 use crate::hint;
 use crate::intrinsics;
 use crate::mem;
-use crate::ops::{Add, Mul, Sub};
 use crate::str::FromStr;
 
 // Used because the `?` operator is not allowed in a const context.
@@ -286,17 +285,6 @@ macro_rules! widening_impl {
     };
 }
 
-macro_rules! conv_rhs_for_unchecked_shift {
-    ($SelfT:ty, $x:expr) => {{
-        // If the `as` cast will truncate, ensure we still tell the backend
-        // that the pre-truncation value was also small.
-        if <$SelfT>::BITS < 32 {
-            intrinsics::assume($x <= (<$SelfT>::MAX as u32));
-        }
-        $x as $SelfT
-    }};
-}
-
 impl i8 {
     int_impl! {
         Self = i8,
@@ -1386,51 +1374,19 @@ pub enum FpCategory {
     Normal,
 }
 
-#[doc(hidden)]
-trait FromStrRadixHelper:
-    PartialOrd + Copy + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self>
-{
-    const MIN: Self;
-    fn from_u32(u: u32) -> Self;
-    fn checked_mul(&self, other: u32) -> Option<Self>;
-    fn checked_sub(&self, other: u32) -> Option<Self>;
-    fn checked_add(&self, other: u32) -> Option<Self>;
-}
-
 macro_rules! from_str_radix_int_impl {
     ($($t:ty)*) => {$(
         #[stable(feature = "rust1", since = "1.0.0")]
         impl FromStr for $t {
             type Err = ParseIntError;
             fn from_str(src: &str) -> Result<Self, ParseIntError> {
-                from_str_radix(src, 10)
+                <$t>::from_str_radix(src, 10)
             }
         }
     )*}
 }
 from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
 
-macro_rules! impl_helper_for {
-    ($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
-        const MIN: Self = Self::MIN;
-        #[inline]
-        fn from_u32(u: u32) -> Self { u as Self }
-        #[inline]
-        fn checked_mul(&self, other: u32) -> Option<Self> {
-            Self::checked_mul(*self, other as Self)
-        }
-        #[inline]
-        fn checked_sub(&self, other: u32) -> Option<Self> {
-            Self::checked_sub(*self, other as Self)
-        }
-        #[inline]
-        fn checked_add(&self, other: u32) -> Option<Self> {
-            Self::checked_add(*self, other as Self)
-        }
-    })*)
-}
-impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
-
 /// Determines if a string of text of that length of that radix could be guaranteed to be
 /// stored in the given type T.
 /// Note that if the radix is known to the compiler, it is just the check of digits.len that
@@ -1438,92 +1394,198 @@ impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
 #[doc(hidden)]
 #[inline(always)]
 #[unstable(issue = "none", feature = "std_internals")]
-pub fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
+pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
     radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
 }
 
-fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, ParseIntError> {
-    use self::IntErrorKind::*;
-    use self::ParseIntError as PIE;
+#[track_caller]
+const fn from_str_radix_panic_ct(_radix: u32) -> ! {
+    panic!("from_str_radix_int: must lie in the range `[2, 36]`");
+}
 
-    assert!(
-        (2..=36).contains(&radix),
-        "from_str_radix_int: must lie in the range `[2, 36]` - found {}",
-        radix
-    );
+#[track_caller]
+fn from_str_radix_panic_rt(radix: u32) -> ! {
+    panic!("from_str_radix_int: must lie in the range `[2, 36]` - found {}", radix);
+}
 
-    if src.is_empty() {
-        return Err(PIE { kind: Empty });
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cold]
+#[track_caller]
+const fn from_str_radix_assert(radix: u32) {
+    if 2 > radix || radix > 36 {
+        // The only difference between these two functions is their panic message.
+        intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt);
     }
+}
 
-    let is_signed_ty = T::from_u32(0) > T::MIN;
-
-    // all valid digits are ascii, so we will just iterate over the utf8 bytes
-    // and cast them to chars. .to_digit() will safely return None for anything
-    // other than a valid ascii digit for the given radix, including the first-byte
-    // of multi-byte sequences
-    let src = src.as_bytes();
+macro_rules! from_str_radix {
+    ($($int_ty:ty)+) => {$(
+        impl $int_ty {
+            /// Converts a string slice in a given base to an integer.
+            ///
+            /// The string is expected to be an optional `+` sign
+            /// followed by digits.
+            /// Leading and trailing whitespace represent an error.
+            /// Digits are a subset of these characters, depending on `radix`:
+            ///
+            /// * `0-9`
+            /// * `a-z`
+            /// * `A-Z`
+            ///
+            /// # Panics
+            ///
+            /// This function panics if `radix` is not in the range from 2 to 36.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_str_radix(\"A\", 16), Ok(10));")]
+            /// ```
+            #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")]
+            pub const fn from_str_radix(src: &str, radix: u32) -> Result<$int_ty, ParseIntError> {
+                use self::IntErrorKind::*;
+                use self::ParseIntError as PIE;
+
+                from_str_radix_assert(radix);
+
+                if src.is_empty() {
+                    return Err(PIE { kind: Empty });
+                }
 
-    let (is_positive, digits) = match src[0] {
-        b'+' | b'-' if src[1..].is_empty() => {
-            return Err(PIE { kind: InvalidDigit });
-        }
-        b'+' => (true, &src[1..]),
-        b'-' if is_signed_ty => (false, &src[1..]),
-        _ => (true, src),
-    };
+                #[allow(unused_comparisons)]
+                let is_signed_ty = 0 > <$int_ty>::MIN;
+
+                // all valid digits are ascii, so we will just iterate over the utf8 bytes
+                // and cast them to chars. .to_digit() will safely return None for anything
+                // other than a valid ascii digit for the given radix, including the first-byte
+                // of multi-byte sequences
+                let src = src.as_bytes();
+
+                let (is_positive, mut digits) = match src {
+                    [b'+' | b'-'] => {
+                        return Err(PIE { kind: InvalidDigit });
+                    }
+                    [b'+', rest @ ..] => (true, rest),
+                    [b'-', rest @ ..] if is_signed_ty => (false, rest),
+                    _ => (true, src),
+                };
+
+                let mut result = 0;
+
+                macro_rules! unwrap_or_PIE {
+                    ($option:expr, $kind:ident) => {
+                        match $option {
+                            Some(value) => value,
+                            None => return Err(PIE { kind: $kind }),
+                        }
+                    };
+                }
 
-    let mut result = T::from_u32(0);
-
-    if can_not_overflow::<T>(radix, is_signed_ty, digits) {
-        // If the len of the str is short compared to the range of the type
-        // we are parsing into, then we can be certain that an overflow will not occur.
-        // This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition
-        // above is a faster (conservative) approximation of this.
-        //
-        // Consider radix 16 as it has the highest information density per digit and will thus overflow the earliest:
-        // `u8::MAX` is `ff` - any str of len 2 is guaranteed to not overflow.
-        // `i8::MAX` is `7f` - only a str of len 1 is guaranteed to not overflow.
-        macro_rules! run_unchecked_loop {
-            ($unchecked_additive_op:expr) => {
-                for &c in digits {
-                    result = result * T::from_u32(radix);
-                    let x = (c as char).to_digit(radix).ok_or(PIE { kind: InvalidDigit })?;
-                    result = $unchecked_additive_op(result, T::from_u32(x));
+                if can_not_overflow::<$int_ty>(radix, is_signed_ty, digits) {
+                    // If the len of the str is short compared to the range of the type
+                    // we are parsing into, then we can be certain that an overflow will not occur.
+                    // This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition
+                    // above is a faster (conservative) approximation of this.
+                    //
+                    // Consider radix 16 as it has the highest information density per digit and will thus overflow the earliest:
+                    // `u8::MAX` is `ff` - any str of len 2 is guaranteed to not overflow.
+                    // `i8::MAX` is `7f` - only a str of len 1 is guaranteed to not overflow.
+                    macro_rules! run_unchecked_loop {
+                        ($unchecked_additive_op:tt) => {{
+                            while let [c, rest @ ..] = digits {
+                                result = result * (radix as $int_ty);
+                                let x = unwrap_or_PIE!((*c as char).to_digit(radix), InvalidDigit);
+                                result = result $unchecked_additive_op (x as $int_ty);
+                                digits = rest;
+                            }
+                        }};
+                    }
+                    if is_positive {
+                        run_unchecked_loop!(+)
+                    } else {
+                        run_unchecked_loop!(-)
+                    };
+                } else {
+                    macro_rules! run_checked_loop {
+                        ($checked_additive_op:ident, $overflow_err:ident) => {{
+                            while let [c, rest @ ..] = digits {
+                                // When `radix` is passed in as a literal, rather than doing a slow `imul`
+                                // the compiler can use shifts if `radix` can be expressed as a
+                                // sum of powers of 2 (x*10 can be written as x*8 + x*2).
+                                // When the compiler can't use these optimisations,
+                                // the latency of the multiplication can be hidden by issuing it
+                                // before the result is needed to improve performance on
+                                // modern out-of-order CPU as multiplication here is slower
+                                // than the other instructions, we can get the end result faster
+                                // doing multiplication first and let the CPU spends other cycles
+                                // doing other computation and get multiplication result later.
+                                let mul = result.checked_mul(radix as $int_ty);
+                                let x = unwrap_or_PIE!((*c as char).to_digit(radix), InvalidDigit) as $int_ty;
+                                result = unwrap_or_PIE!(mul, $overflow_err);
+                                result = unwrap_or_PIE!(<$int_ty>::$checked_additive_op(result, x), $overflow_err);
+                                digits = rest;
+                            }
+                        }};
+                    }
+                    if is_positive {
+                        run_checked_loop!(checked_add, PosOverflow)
+                    } else {
+                        run_checked_loop!(checked_sub, NegOverflow)
+                    };
                 }
-            };
+                Ok(result)
+            }
         }
-        if is_positive {
-            run_unchecked_loop!(<T as core::ops::Add>::add)
-        } else {
-            run_unchecked_loop!(<T as core::ops::Sub>::sub)
-        };
-    } else {
-        macro_rules! run_checked_loop {
-            ($checked_additive_op:ident, $overflow_err:expr) => {
-                for &c in digits {
-                    // When `radix` is passed in as a literal, rather than doing a slow `imul`
-                    // the compiler can use shifts if `radix` can be expressed as a
-                    // sum of powers of 2 (x*10 can be written as x*8 + x*2).
-                    // When the compiler can't use these optimisations,
-                    // the latency of the multiplication can be hidden by issuing it
-                    // before the result is needed to improve performance on
-                    // modern out-of-order CPU as multiplication here is slower
-                    // than the other instructions, we can get the end result faster
-                    // doing multiplication first and let the CPU spends other cycles
-                    // doing other computation and get multiplication result later.
-                    let mul = result.checked_mul(radix);
-                    let x = (c as char).to_digit(radix).ok_or(PIE { kind: InvalidDigit })?;
-                    result = mul.ok_or_else($overflow_err)?;
-                    result = T::$checked_additive_op(&result, x).ok_or_else($overflow_err)?;
-                }
-            };
+    )+}
+}
+
+from_str_radix! { i8 u8 i16 u16 i32 u32 i64 u64 i128 u128 }
+
+// Re-use the relevant implementation of from_str_radix for isize and usize to avoid outputting two
+// identical functions.
+macro_rules! from_str_radix_size_impl {
+    ($($t:ident $size:ty),*) => {$(
+    impl $size {
+        /// Converts a string slice in a given base to an integer.
+        ///
+        /// The string is expected to be an optional `+` sign
+        /// followed by digits.
+        /// Leading and trailing whitespace represent an error.
+        /// Digits are a subset of these characters, depending on `radix`:
+        ///
+        /// * `0-9`
+        /// * `a-z`
+        /// * `A-Z`
+        ///
+        /// # Panics
+        ///
+        /// This function panics if `radix` is not in the range from 2 to 36.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(", stringify!($size), "::from_str_radix(\"A\", 16), Ok(10));")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")]
+        pub const fn from_str_radix(src: &str, radix: u32) -> Result<$size, ParseIntError> {
+            match <$t>::from_str_radix(src, radix) {
+                Ok(x) => Ok(x as $size),
+                Err(e) => Err(e),
+            }
         }
-        if is_positive {
-            run_checked_loop!(checked_add, || PIE { kind: PosOverflow })
-        } else {
-            run_checked_loop!(checked_sub, || PIE { kind: NegOverflow })
-        };
-    }
-    Ok(result)
+    })*}
 }
+
+#[cfg(target_pointer_width = "16")]
+from_str_radix_size_impl! { i16 isize, u16 usize }
+#[cfg(target_pointer_width = "32")]
+from_str_radix_size_impl! { i32 isize, u32 usize }
+#[cfg(target_pointer_width = "64")]
+from_str_radix_size_impl! { i64 isize, u64 usize }
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 1171407c07a..62ea7abf652 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -11,7 +11,6 @@ use crate::ptr;
 use crate::str::FromStr;
 use crate::ub_checks;
 
-use super::from_str_radix;
 use super::{IntErrorKind, ParseIntError};
 
 /// A marker trait for primitive types which can be zero.
@@ -804,7 +803,7 @@ macro_rules! nonzero_integer {
         impl FromStr for $Ty {
             type Err = ParseIntError;
             fn from_str(src: &str) -> Result<Self, Self::Err> {
-                Self::new(from_str_radix(src, 10)?)
+                Self::new(<$Int>::from_str_radix(src, 10)?)
                     .ok_or(ParseIntError {
                         kind: IntErrorKind::Zero
                     })
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 081a3c0b118..ba6a243041c 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -58,33 +58,6 @@ macro_rules! uint_impl {
         #[stable(feature = "int_bits_const", since = "1.53.0")]
         pub const BITS: u32 = Self::MAX.count_ones();
 
-        /// Converts a string slice in a given base to an integer.
-        ///
-        /// The string is expected to be an optional `+` sign
-        /// followed by digits.
-        /// Leading and trailing whitespace represent an error.
-        /// Digits are a subset of these characters, depending on `radix`:
-        ///
-        /// * `0-9`
-        /// * `a-z`
-        /// * `A-Z`
-        ///
-        /// # Panics
-        ///
-        /// This function panics if `radix` is not in the range from 2 to 36.
-        ///
-        /// # Examples
-        ///
-        /// Basic usage:
-        ///
-        /// ```
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")]
-        /// ```
-        #[stable(feature = "rust1", since = "1.0.0")]
-        pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
-            from_str_radix(src, radix)
-        }
-
         /// Returns the number of ones in the binary representation of `self`.
         ///
         /// # Examples
@@ -500,21 +473,25 @@ macro_rules! uint_impl {
         /// Unchecked integer addition. Computes `self + rhs`, assuming overflow
         /// cannot occur.
         ///
+        /// Calling `x.unchecked_add(y)` is semantically equivalent to calling
+        /// `x.`[`checked_add`]`(y).`[`unwrap_unchecked`]`()`.
+        ///
+        /// If you're just trying to avoid the panic in debug mode, then **do not**
+        /// use this.  Instead, you're looking for [`wrapping_add`].
+        ///
         /// # Safety
         ///
         /// This results in undefined behavior when
         #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")]
         /// i.e. when [`checked_add`] would return `None`.
         ///
+        /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked
         #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")]
-        #[unstable(
-            feature = "unchecked_math",
-            reason = "niche optimization path",
-            issue = "85122",
-        )]
+        #[doc = concat!("[`wrapping_add`]: ", stringify!($SelfT), "::wrapping_add")]
+        #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_const_unstable(feature = "unchecked_math", issue = "85122")]
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
@@ -644,21 +621,25 @@ macro_rules! uint_impl {
         /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
         /// cannot occur.
         ///
+        /// Calling `x.unchecked_sub(y)` is semantically equivalent to calling
+        /// `x.`[`checked_sub`]`(y).`[`unwrap_unchecked`]`()`.
+        ///
+        /// If you're just trying to avoid the panic in debug mode, then **do not**
+        /// use this.  Instead, you're looking for [`wrapping_sub`].
+        ///
         /// # Safety
         ///
         /// This results in undefined behavior when
         #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")]
         /// i.e. when [`checked_sub`] would return `None`.
         ///
+        /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked
         #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")]
-        #[unstable(
-            feature = "unchecked_math",
-            reason = "niche optimization path",
-            issue = "85122",
-        )]
+        #[doc = concat!("[`wrapping_sub`]: ", stringify!($SelfT), "::wrapping_sub")]
+        #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_const_unstable(feature = "unchecked_math", issue = "85122")]
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
@@ -726,21 +707,25 @@ macro_rules! uint_impl {
         /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
         /// cannot occur.
         ///
+        /// Calling `x.unchecked_mul(y)` is semantically equivalent to calling
+        /// `x.`[`checked_mul`]`(y).`[`unwrap_unchecked`]`()`.
+        ///
+        /// If you're just trying to avoid the panic in debug mode, then **do not**
+        /// use this.  Instead, you're looking for [`wrapping_mul`].
+        ///
         /// # Safety
         ///
         /// This results in undefined behavior when
         #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")]
         /// i.e. when [`checked_mul`] would return `None`.
         ///
+        /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked
         #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")]
-        #[unstable(
-            feature = "unchecked_math",
-            reason = "niche optimization path",
-            issue = "85122",
-        )]
+        #[doc = concat!("[`wrapping_mul`]: ", stringify!($SelfT), "::wrapping_mul")]
+        #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_const_unstable(feature = "unchecked_math", issue = "85122")]
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
@@ -1301,10 +1286,18 @@ macro_rules! uint_impl {
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
-            // SAFETY: the caller must uphold the safety contract for
-            // `unchecked_shl`.
-            // Any legal shift amount is losslessly representable in the self type.
-            unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
+            #[cfg(bootstrap)]
+            {
+                // For bootstrapping, just use built-in primitive shift.
+                // panicking is a legal manifestation of UB
+                self << rhs
+            }
+            #[cfg(not(bootstrap))]
+            {
+                // SAFETY: the caller must uphold the safety contract for
+                // `unchecked_shl`.
+                unsafe { intrinsics::unchecked_shl(self, rhs) }
+            }
         }
 
         /// Checked shift right. Computes `self >> rhs`, returning `None`
@@ -1384,10 +1377,18 @@ macro_rules! uint_impl {
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
-            // SAFETY: the caller must uphold the safety contract for
-            // `unchecked_shr`.
-            // Any legal shift amount is losslessly representable in the self type.
-            unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
+            #[cfg(bootstrap)]
+            {
+                // For bootstrapping, just use built-in primitive shift.
+                // panicking is a legal manifestation of UB
+                self >> rhs
+            }
+            #[cfg(not(bootstrap))]
+            {
+                // SAFETY: the caller must uphold the safety contract for
+                // `unchecked_shr`.
+                unsafe { intrinsics::unchecked_shr(self, rhs) }
+            }
         }
 
         /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index a6c00ff28d4..01db050e666 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -136,7 +136,7 @@ impl<T: ?Sized> *const T {
     #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
     #[deprecated(
         since = "1.67.0",
-        note = "replaced by the `expose_addr` method, or update your code \
+        note = "replaced by the `expose_provenance` method, or update your code \
             to follow the strict provenance rules using its APIs"
     )]
     #[inline(always)]
@@ -165,7 +165,7 @@ impl<T: ?Sized> *const T {
     #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
     #[deprecated(
         since = "1.67.0",
-        note = "replaced by the `ptr::from_exposed_addr` function, or update \
+        note = "replaced by the `ptr::with_exposed_provenance` function, or update \
             your code to follow the strict provenance rules using its APIs"
     )]
     #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function
@@ -187,7 +187,7 @@ impl<T: ?Sized> *const T {
     ///
     /// If using those APIs is not possible because there is no way to preserve a pointer with the
     /// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
-    /// or [`expose_addr`][pointer::expose_addr] and [`from_exposed_addr`][from_exposed_addr]
+    /// or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance]
     /// instead. However, note that this makes your code less portable and less amenable to tools
     /// that check for compliance with the Rust memory model.
     ///
@@ -210,35 +210,35 @@ impl<T: ?Sized> *const T {
         unsafe { mem::transmute(self.cast::<()>()) }
     }
 
-    /// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future
-    /// use in [`from_exposed_addr`][].
+    /// Exposes the "provenance" part of the pointer for future use in
+    /// [`with_exposed_provenance`][] and returns the "address" portion.
     ///
     /// This is equivalent to `self as usize`, which semantically discards *provenance* and
     /// *address-space* information. Furthermore, this (like the `as` cast) has the implicit
     /// side-effect of marking the provenance as 'exposed', so on platforms that support it you can
-    /// later call [`from_exposed_addr`][] to reconstitute the original pointer including its
+    /// later call [`with_exposed_provenance`][] to reconstitute the original pointer including its
     /// provenance. (Reconstructing address space information, if required, is your responsibility.)
     ///
     /// Using this method means that code is *not* following [Strict
     /// Provenance][super#strict-provenance] rules. Supporting
-    /// [`from_exposed_addr`][] complicates specification and reasoning and may not be supported by
+    /// [`with_exposed_provenance`][] complicates specification and reasoning and may not be supported by
     /// tools that help you to stay conformant with the Rust memory model, so it is recommended to
     /// use [`addr`][pointer::addr] wherever possible.
     ///
     /// On most platforms this will produce a value with the same bytes as the original pointer,
     /// because all the bytes are dedicated to describing the address. Platforms which need to store
     /// additional information in the pointer may not support this operation, since the 'expose'
-    /// side-effect which is required for [`from_exposed_addr`][] to work is typically not
+    /// side-effect which is required for [`with_exposed_provenance`][] to work is typically not
     /// available.
     ///
     /// It is unclear whether this method can be given a satisfying unambiguous specification. This
     /// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
     ///
-    /// [`from_exposed_addr`]: from_exposed_addr
+    /// [`with_exposed_provenance`]: with_exposed_provenance
     #[must_use]
     #[inline(always)]
     #[unstable(feature = "exposed_provenance", issue = "95228")]
-    pub fn expose_addr(self) -> usize {
+    pub fn expose_provenance(self) -> usize {
         // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
         self.cast::<()>() as usize
     }
@@ -1029,8 +1029,6 @@ impl<T: ?Sized> *const T {
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
-    // We could always go back to wrapping if unchecked becomes unacceptable
-    #[rustc_allow_const_fn_unstable(const_int_unchecked_arith)]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn sub(self, count: usize) -> Self
@@ -1403,8 +1401,6 @@ impl<T: ?Sized> *const T {
     /// # Examples
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
-    ///
     /// // On some platforms, the alignment of i32 is less than 4.
     /// #[repr(align(4))]
     /// struct AlignedI32(i32);
@@ -1427,7 +1423,6 @@ impl<T: ?Sized> *const T {
     /// underlying allocation.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// // On some platforms, the alignment of primitives is less than their size.
@@ -1453,7 +1448,6 @@ impl<T: ?Sized> *const T {
     /// pointer is aligned, even if the compiletime pointer wasn't aligned.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// // On some platforms, the alignment of primitives is less than their size.
@@ -1479,7 +1473,6 @@ impl<T: ?Sized> *const T {
     /// runtime and compiletime.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// // On some platforms, the alignment of primitives is less than their size.
@@ -1503,7 +1496,7 @@ impl<T: ?Sized> *const T {
     /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
     #[must_use]
     #[inline]
-    #[unstable(feature = "pointer_is_aligned", issue = "96284")]
+    #[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
     pub const fn is_aligned(self) -> bool
     where
@@ -1524,7 +1517,7 @@ impl<T: ?Sized> *const T {
     /// # Examples
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     ///
     /// // On some platforms, the alignment of i32 is less than 4.
     /// #[repr(align(4))]
@@ -1553,7 +1546,7 @@ impl<T: ?Sized> *const T {
     /// cannot be stricter aligned than the reference's underlying allocation.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// // On some platforms, the alignment of i32 is less than 4.
@@ -1578,7 +1571,7 @@ impl<T: ?Sized> *const T {
     /// pointer is aligned, even if the compiletime pointer wasn't aligned.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// // On some platforms, the alignment of i32 is less than 4.
@@ -1602,7 +1595,7 @@ impl<T: ?Sized> *const T {
     /// runtime and compiletime.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// const _: () = {
@@ -1618,7 +1611,7 @@ impl<T: ?Sized> *const T {
     /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
     #[must_use]
     #[inline]
-    #[unstable(feature = "pointer_is_aligned", issue = "96284")]
+    #[unstable(feature = "pointer_is_aligned_to", issue = "96284")]
     #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
     pub const fn is_aligned_to(self, align: usize) -> bool {
         if !align.is_power_of_two() {
@@ -1857,6 +1850,7 @@ impl<T: ?Sized> Ord for *const T {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialOrd for *const T {
     #[inline]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn partial_cmp(&self, other: &*const T) -> Option<Ordering> {
         Some(self.cmp(other))
     }
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index fe19f66a31a..9b5da935e07 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -57,7 +57,7 @@ pub trait Pointee {
     // NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
     // in `library/core/src/ptr/metadata.rs`
     // in sync with those here:
-    type Metadata: Copy + Send + Sync + Ord + Hash + Unpin;
+    type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin;
 }
 
 /// Pointers to types implementing this trait alias are “thin”.
@@ -258,6 +258,7 @@ impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
 
 impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
     #[inline]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
         (self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
     }
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 56378b437e7..f12ab3d50cd 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -340,13 +340,13 @@
 //! clear where a satisfying unambiguous semantics can be defined for Exposed Provenance.
 //! Furthermore, Exposed Provenance will not work (well) with tools like [Miri] and [CHERI].
 //!
-//! Exposed Provenance is provided by the [`expose_addr`] and [`from_exposed_addr`] methods, which
-//! are meant to replace `as` casts between pointers and integers. [`expose_addr`] is a lot like
+//! Exposed Provenance is provided by the [`expose_provenance`] and [`with_exposed_provenance`] methods,
+//! which are meant to replace `as` casts between pointers and integers. [`expose_provenance`] is a lot like
 //! [`addr`], but additionally adds the provenance of the pointer to a global list of 'exposed'
 //! provenances. (This list is purely conceptual, it exists for the purpose of specifying Rust but
-//! is not materialized in actual executions, except in tools like [Miri].) [`from_exposed_addr`]
+//! is not materialized in actual executions, except in tools like [Miri].) [`with_exposed_provenance`]
 //! can be used to construct a pointer with one of these previously 'exposed' provenances.
-//! [`from_exposed_addr`] takes only `addr: usize` as arguments, so unlike in [`with_addr`] there is
+//! [`with_exposed_provenance`] takes only `addr: usize` as arguments, so unlike in [`with_addr`] there is
 //! no indication of what the correct provenance for the returned pointer is -- and that is exactly
 //! what makes pointer-usize-pointer roundtrips so tricky to rigorously specify! There is no
 //! algorithm that decides which provenance will be used. You can think of this as "guessing" the
@@ -355,10 +355,10 @@
 //! there is *no* previously 'exposed' provenance that justifies the way the returned pointer will
 //! be used, the program has undefined behavior.
 //!
-//! Using [`expose_addr`] or [`from_exposed_addr`] (or the `as` casts) means that code is
+//! Using [`expose_provenance`] or [`with_exposed_provenance`] (or the `as` casts) means that code is
 //! *not* following Strict Provenance rules. The goal of the Strict Provenance experiment is to
-//! determine how far one can get in Rust without the use of [`expose_addr`] and
-//! [`from_exposed_addr`], and to encourage code to be written with Strict Provenance APIs only.
+//! determine how far one can get in Rust without the use of [`expose_provenance`] and
+//! [`with_exposed_provenance`], and to encourage code to be written with Strict Provenance APIs only.
 //! Maximizing the amount of such code is a major win for avoiding specification complexity and to
 //! facilitate adoption of tools like [CHERI] and [Miri] that can be a big help in increasing the
 //! confidence in (unsafe) Rust code.
@@ -374,8 +374,8 @@
 //! [`map_addr`]: pointer::map_addr
 //! [`addr`]: pointer::addr
 //! [`ptr::dangling`]: core::ptr::dangling
-//! [`expose_addr`]: pointer::expose_addr
-//! [`from_exposed_addr`]: from_exposed_addr
+//! [`expose_provenance`]: pointer::expose_provenance
+//! [`with_exposed_provenance`]: with_exposed_provenance
 //! [Miri]: https://github.com/rust-lang/miri
 //! [CHERI]: https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/
 //! [Strict Provenance]: https://github.com/rust-lang/rust/issues/95228
@@ -581,7 +581,7 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
 /// little more than a usize address in disguise.
 ///
 /// This is different from `addr as *const T`, which creates a pointer that picks up a previously
-/// exposed provenance. See [`from_exposed_addr`] for more details on that operation.
+/// exposed provenance. See [`with_exposed_provenance`] for more details on that operation.
 ///
 /// This API and its claimed semantics are part of the Strict Provenance experiment,
 /// see the [module documentation][crate::ptr] for details.
@@ -592,7 +592,7 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
 pub const fn without_provenance<T>(addr: usize) -> *const T {
     // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
     // We use transmute rather than a cast so tools like Miri can tell that this
-    // is *not* the same as from_exposed_addr.
+    // is *not* the same as with_exposed_provenance.
     // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
     // pointer).
     unsafe { mem::transmute(addr) }
@@ -625,7 +625,7 @@ pub const fn dangling<T>() -> *const T {
 /// little more than a usize address in disguise.
 ///
 /// This is different from `addr as *mut T`, which creates a pointer that picks up a previously
-/// exposed provenance. See [`from_exposed_addr_mut`] for more details on that operation.
+/// exposed provenance. See [`with_exposed_provenance_mut`] for more details on that operation.
 ///
 /// This API and its claimed semantics are part of the Strict Provenance experiment,
 /// see the [module documentation][crate::ptr] for details.
@@ -636,7 +636,7 @@ pub const fn dangling<T>() -> *const T {
 pub const fn without_provenance_mut<T>(addr: usize) -> *mut T {
     // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
     // We use transmute rather than a cast so tools like Miri can tell that this
-    // is *not* the same as from_exposed_addr.
+    // is *not* the same as with_exposed_provenance.
     // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
     // pointer).
     unsafe { mem::transmute(addr) }
@@ -663,7 +663,7 @@ pub const fn dangling_mut<T>() -> *mut T {
 ///
 /// This is a more rigorously specified alternative to `addr as *const T`. The provenance of the
 /// returned pointer is that of *any* pointer that was previously exposed by passing it to
-/// [`expose_addr`][pointer::expose_addr], or a `ptr as usize` cast. In addition, memory which is
+/// [`expose_provenance`][pointer::expose_provenance], or a `ptr as usize` cast. In addition, memory which is
 /// outside the control of the Rust abstract machine (MMIO registers, for example) is always
 /// considered to be exposed, so long as this memory is disjoint from memory that will be used by
 /// the abstract machine such as the stack, heap, and statics.
@@ -699,7 +699,7 @@ pub const fn dangling_mut<T>() -> *mut T {
 #[unstable(feature = "exposed_provenance", issue = "95228")]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
-pub fn from_exposed_addr<T>(addr: usize) -> *const T
+pub fn with_exposed_provenance<T>(addr: usize) -> *const T
 where
     T: Sized,
 {
@@ -711,7 +711,7 @@ where
 ///
 /// This is a more rigorously specified alternative to `addr as *mut T`. The provenance of the
 /// returned pointer is that of *any* pointer that was previously passed to
-/// [`expose_addr`][pointer::expose_addr] or a `ptr as usize` cast. If there is no previously
+/// [`expose_provenance`][pointer::expose_provenance] or a `ptr as usize` cast. If there is no previously
 /// 'exposed' provenance that justifies the way this pointer will be used, the program has undefined
 /// behavior. Note that there is no algorithm that decides which provenance will be used. You can
 /// think of this as "guessing" the right provenance, and the guess will be "maximally in your
@@ -739,7 +739,7 @@ where
 #[unstable(feature = "exposed_provenance", issue = "95228")]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
-pub fn from_exposed_addr_mut<T>(addr: usize) -> *mut T
+pub fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T
 where
     T: Sized,
 {
@@ -1781,9 +1781,19 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
     // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
     // 1, where the method versions of these operations are not inlined.
     use intrinsics::{
-        assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_shl,
-        unchecked_shr, unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub,
+        assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_sub,
+        wrapping_add, wrapping_mul, wrapping_sub,
     };
+    #[cfg(bootstrap)]
+    const unsafe fn unchecked_shl(value: usize, shift: usize) -> usize {
+        value << shift
+    }
+    #[cfg(bootstrap)]
+    const unsafe fn unchecked_shr(value: usize, shift: usize) -> usize {
+        value >> shift
+    }
+    #[cfg(not(bootstrap))]
+    use intrinsics::{unchecked_shl, unchecked_shr};
 
     /// Calculate multiplicative modular inverse of `x` modulo `m`.
     ///
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 1add9ca2311..41e5ba67458 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -142,7 +142,7 @@ impl<T: ?Sized> *mut T {
     #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
     #[deprecated(
         since = "1.67.0",
-        note = "replaced by the `expose_addr` method, or update your code \
+        note = "replaced by the `expose_provenance` method, or update your code \
             to follow the strict provenance rules using its APIs"
     )]
     #[inline(always)]
@@ -171,7 +171,7 @@ impl<T: ?Sized> *mut T {
     #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
     #[deprecated(
         since = "1.67.0",
-        note = "replaced by the `ptr::from_exposed_addr_mut` function, or \
+        note = "replaced by the `ptr::with_exposed_provenance_mut` function, or \
             update your code to follow the strict provenance rules using its APIs"
     )]
     #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function
@@ -194,7 +194,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// If using those APIs is not possible because there is no way to preserve a pointer with the
     /// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
-    /// or [`expose_addr`][pointer::expose_addr] and [`from_exposed_addr`][from_exposed_addr]
+    /// or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance]
     /// instead. However, note that this makes your code less portable and less amenable to tools
     /// that check for compliance with the Rust memory model.
     ///
@@ -217,35 +217,34 @@ impl<T: ?Sized> *mut T {
         unsafe { mem::transmute(self.cast::<()>()) }
     }
 
-    /// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future
-    /// use in [`from_exposed_addr`][].
+    /// Exposes the "provenance" part of the pointer for future use in
+    /// [`with_exposed_provenance`][] and returns the "address" portion.
     ///
     /// This is equivalent to `self as usize`, which semantically discards *provenance* and
     /// *address-space* information. Furthermore, this (like the `as` cast) has the implicit
     /// side-effect of marking the provenance as 'exposed', so on platforms that support it you can
-    /// later call [`from_exposed_addr_mut`][] to reconstitute the original pointer including its
+    /// later call [`with_exposed_provenance_mut`][] to reconstitute the original pointer including its
     /// provenance. (Reconstructing address space information, if required, is your responsibility.)
     ///
     /// Using this method means that code is *not* following [Strict
     /// Provenance][super#strict-provenance] rules. Supporting
-    /// [`from_exposed_addr_mut`][] complicates specification and reasoning and may not be supported
+    /// [`with_exposed_provenance_mut`][] complicates specification and reasoning and may not be supported
     /// by tools that help you to stay conformant with the Rust memory model, so it is recommended
     /// to use [`addr`][pointer::addr] wherever possible.
     ///
     /// On most platforms this will produce a value with the same bytes as the original pointer,
     /// because all the bytes are dedicated to describing the address. Platforms which need to store
     /// additional information in the pointer may not support this operation, since the 'expose'
-    /// side-effect which is required for [`from_exposed_addr_mut`][] to work is typically not
+    /// side-effect which is required for [`with_exposed_provenance_mut`][] to work is typically not
     /// available.
     ///
     /// It is unclear whether this method can be given a satisfying unambiguous specification. This
     /// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
     ///
-    /// [`from_exposed_addr_mut`]: from_exposed_addr_mut
-    #[must_use]
+    /// [`with_exposed_provenance_mut`]: with_exposed_provenance_mut
     #[inline(always)]
     #[unstable(feature = "exposed_provenance", issue = "95228")]
-    pub fn expose_addr(self) -> usize {
+    pub fn expose_provenance(self) -> usize {
         // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
         self.cast::<()>() as usize
     }
@@ -1119,8 +1118,6 @@ impl<T: ?Sized> *mut T {
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
-    // We could always go back to wrapping if unchecked becomes unacceptable
-    #[rustc_allow_const_fn_unstable(const_int_unchecked_arith)]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn sub(self, count: usize) -> Self
@@ -1662,8 +1659,6 @@ impl<T: ?Sized> *mut T {
     /// # Examples
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
-    ///
     /// // On some platforms, the alignment of i32 is less than 4.
     /// #[repr(align(4))]
     /// struct AlignedI32(i32);
@@ -1686,7 +1681,6 @@ impl<T: ?Sized> *mut T {
     /// underlying allocation.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     /// #![feature(const_mut_refs)]
     ///
@@ -1713,7 +1707,6 @@ impl<T: ?Sized> *mut T {
     /// pointer is aligned, even if the compiletime pointer wasn't aligned.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// // On some platforms, the alignment of primitives is less than their size.
@@ -1740,7 +1733,6 @@ impl<T: ?Sized> *mut T {
     /// runtime and compiletime.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// // On some platforms, the alignment of primitives is less than their size.
@@ -1764,7 +1756,7 @@ impl<T: ?Sized> *mut T {
     /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
     #[must_use]
     #[inline]
-    #[unstable(feature = "pointer_is_aligned", issue = "96284")]
+    #[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
     pub const fn is_aligned(self) -> bool
     where
@@ -1785,7 +1777,7 @@ impl<T: ?Sized> *mut T {
     /// # Examples
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     ///
     /// // On some platforms, the alignment of i32 is less than 4.
     /// #[repr(align(4))]
@@ -1814,7 +1806,7 @@ impl<T: ?Sized> *mut T {
     /// cannot be stricter aligned than the reference's underlying allocation.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     /// #![feature(const_pointer_is_aligned)]
     /// #![feature(const_mut_refs)]
     ///
@@ -1840,7 +1832,7 @@ impl<T: ?Sized> *mut T {
     /// pointer is aligned, even if the compiletime pointer wasn't aligned.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// // On some platforms, the alignment of i32 is less than 4.
@@ -1865,7 +1857,7 @@ impl<T: ?Sized> *mut T {
     /// runtime and compiletime.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// const _: () = {
@@ -1881,7 +1873,7 @@ impl<T: ?Sized> *mut T {
     /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
     #[must_use]
     #[inline]
-    #[unstable(feature = "pointer_is_aligned", issue = "96284")]
+    #[unstable(feature = "pointer_is_aligned_to", issue = "96284")]
     #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
     pub const fn is_aligned_to(self, align: usize) -> bool {
         if !align.is_power_of_two() {
@@ -2275,6 +2267,7 @@ impl<T: ?Sized> Ord for *mut T {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialOrd for *mut T {
     #[inline(always)]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn partial_cmp(&self, other: &*mut T) -> Option<Ordering> {
         Some(self.cmp(other))
     }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index e9488917acc..f0e4b958bc6 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -702,8 +702,6 @@ impl<T: ?Sized> NonNull<T> {
     #[unstable(feature = "non_null_convenience", issue = "117691")]
     #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
-    // We could always go back to wrapping if unchecked becomes unacceptable
-    #[rustc_allow_const_fn_unstable(const_int_unchecked_arith)]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn sub(self, count: usize) -> Self
@@ -1290,7 +1288,6 @@ impl<T: ?Sized> NonNull<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// use std::ptr::NonNull;
     ///
     /// // On some platforms, the alignment of i32 is less than 4.
@@ -1315,7 +1312,6 @@ impl<T: ?Sized> NonNull<T> {
     /// underlying allocation.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     /// #![feature(non_null_convenience)]
     /// #![feature(const_option)]
@@ -1345,7 +1341,6 @@ impl<T: ?Sized> NonNull<T> {
     /// pointer is aligned, even if the compiletime pointer wasn't aligned.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// // On some platforms, the alignment of primitives is less than their size.
@@ -1371,7 +1366,6 @@ impl<T: ?Sized> NonNull<T> {
     /// runtime and compiletime.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     /// #![feature(const_option)]
     /// #![feature(const_nonnull_new)]
@@ -1396,7 +1390,7 @@ impl<T: ?Sized> NonNull<T> {
     /// ```
     ///
     /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
-    #[unstable(feature = "pointer_is_aligned", issue = "96284")]
+    #[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
     #[must_use]
     #[inline]
@@ -1419,7 +1413,7 @@ impl<T: ?Sized> NonNull<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     ///
     /// // On some platforms, the alignment of i32 is less than 4.
     /// #[repr(align(4))]
@@ -1448,7 +1442,7 @@ impl<T: ?Sized> NonNull<T> {
     /// cannot be stricter aligned than the reference's underlying allocation.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// // On some platforms, the alignment of i32 is less than 4.
@@ -1473,7 +1467,7 @@ impl<T: ?Sized> NonNull<T> {
     /// pointer is aligned, even if the compiletime pointer wasn't aligned.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// // On some platforms, the alignment of i32 is less than 4.
@@ -1497,7 +1491,7 @@ impl<T: ?Sized> NonNull<T> {
     /// runtime and compiletime.
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
+    /// #![feature(pointer_is_aligned_to)]
     /// #![feature(const_pointer_is_aligned)]
     ///
     /// const _: () = {
@@ -1511,7 +1505,7 @@ impl<T: ?Sized> NonNull<T> {
     /// ```
     ///
     /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
-    #[unstable(feature = "pointer_is_aligned", issue = "96284")]
+    #[unstable(feature = "pointer_is_aligned_to", issue = "96284")]
     #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
     #[must_use]
     #[inline]
@@ -1821,6 +1815,7 @@ impl<T: ?Sized> PartialEq for NonNull<T> {
 #[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized> Ord for NonNull<T> {
     #[inline]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn cmp(&self, other: &Self) -> Ordering {
         self.as_ptr().cmp(&other.as_ptr())
     }
@@ -1829,6 +1824,7 @@ impl<T: ?Sized> Ord for NonNull<T> {
 #[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized> PartialOrd for NonNull<T> {
     #[inline]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
         self.as_ptr().partial_cmp(&other.as_ptr())
     }
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index 127a407dae5..8d7b6165510 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -195,6 +195,7 @@ pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
     fn index_mut(self, slice: &mut T) -> &mut Self::Output;
 }
 
+/// The methods `index` and `index_mut` panic if the index is out of bounds.
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
 unsafe impl<T> SliceIndex<[T]> for usize {
@@ -328,6 +329,9 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
     }
 }
 
+/// The methods `index` and `index_mut` panic if:
+/// - the start of the range is greater than the end of the range or
+/// - the end of the range is out of bounds.
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
 unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
@@ -416,6 +420,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
     }
 }
 
+/// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
 unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
@@ -454,6 +459,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
     }
 }
 
+/// The methods `index` and `index_mut` panic if the start of the range is out of bounds.
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
 unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
@@ -536,6 +542,10 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
     }
 }
 
+/// The methods `index` and `index_mut` panic if:
+/// - the end of the range is `usize::MAX` or
+/// - the start of the range is greater than the end of the range or
+/// - the end of the range is out of bounds.
 #[stable(feature = "inclusive_range", since = "1.26.0")]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
 unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
@@ -580,6 +590,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
     }
 }
 
+/// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
 #[stable(feature = "inclusive_range", since = "1.26.0")]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
 unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index a16005abf46..6e1ba74f72b 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -2724,8 +2724,10 @@ impl<T> [T] {
     /// ```
     /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
     /// let num = 42;
-    /// let idx = s.partition_point(|&x| x < num);
-    /// // The above is equivalent to `let idx = s.binary_search(&num).unwrap_or_else(|x| x);`
+    /// let idx = s.partition_point(|&x| x <= num);
+    /// // If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to
+    /// // `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` will allow `insert`
+    /// // to shift less elements.
     /// s.insert(idx, num);
     /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
     /// ```
@@ -4175,7 +4177,7 @@ impl<T> [T] {
     /// ```
     /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
     /// let num = 42;
-    /// let idx = s.partition_point(|&x| x < num);
+    /// let idx = s.partition_point(|&x| x <= num);
     /// s.insert(idx, num);
     /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
     /// ```
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 77002ef87aa..0a749fcb8f9 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -418,14 +418,12 @@ impl AtomicBool {
     /// # Examples
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// use std::sync::atomic::{self, AtomicBool};
-    /// use std::mem::align_of;
     ///
     /// // Get a pointer to an allocated value
     /// let ptr: *mut bool = Box::into_raw(Box::new(false));
     ///
-    /// assert!(ptr.is_aligned_to(align_of::<AtomicBool>()));
+    /// assert!(ptr.cast::<AtomicBool>().is_aligned());
     ///
     /// {
     ///     // Create an atomic view of the allocated value
@@ -1216,14 +1214,12 @@ impl<T> AtomicPtr<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(pointer_is_aligned)]
     /// use std::sync::atomic::{self, AtomicPtr};
-    /// use std::mem::align_of;
     ///
     /// // Get a pointer to an allocated value
     /// let ptr: *mut *mut u8 = Box::into_raw(Box::new(std::ptr::null_mut()));
     ///
-    /// assert!(ptr.is_aligned_to(align_of::<AtomicPtr<u8>>()));
+    /// assert!(ptr.cast::<AtomicPtr<u8>>().is_aligned());
     ///
     /// {
     ///     // Create an atomic view of the allocated value
@@ -2199,14 +2195,12 @@ macro_rules! atomic_int {
             /// # Examples
             ///
             /// ```
-            /// #![feature(pointer_is_aligned)]
             #[doc = concat!($extra_feature, "use std::sync::atomic::{self, ", stringify!($atomic_type), "};")]
-            /// use std::mem::align_of;
             ///
             /// // Get a pointer to an allocated value
             #[doc = concat!("let ptr: *mut ", stringify!($int_type), " = Box::into_raw(Box::new(0));")]
             ///
-            #[doc = concat!("assert!(ptr.is_aligned_to(align_of::<", stringify!($atomic_type), ">()));")]
+            #[doc = concat!("assert!(ptr.cast::<", stringify!($atomic_type), ">().is_aligned());")]
             ///
             /// {
             ///     // Create an atomic view of the allocated value
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 1b43c46bda5..fe39f6c0b56 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -2,6 +2,7 @@
 
 use crate::mem::transmute;
 
+use crate::any::Any;
 use crate::fmt;
 use crate::marker::PhantomData;
 use crate::ptr;
@@ -220,6 +221,12 @@ impl RawWakerVTable {
     }
 }
 
+#[derive(Debug)]
+enum ExtData<'a> {
+    Some(&'a mut dyn Any),
+    None(()),
+}
+
 /// The context of an asynchronous task.
 ///
 /// Currently, `Context` only serves to provide access to a [`&Waker`](Waker)
@@ -229,6 +236,7 @@ impl RawWakerVTable {
 pub struct Context<'a> {
     waker: &'a Waker,
     local_waker: &'a LocalWaker,
+    ext: ExtData<'a>,
     // Ensure we future-proof against variance changes by forcing
     // the lifetime to be invariant (argument-position lifetimes
     // are contravariant while return-position lifetimes are
@@ -257,6 +265,7 @@ impl<'a> Context<'a> {
     pub const fn waker(&self) -> &'a Waker {
         &self.waker
     }
+
     /// Returns a reference to the [`LocalWaker`] for the current task.
     #[inline]
     #[unstable(feature = "local_waker", issue = "118959")]
@@ -264,6 +273,17 @@ impl<'a> Context<'a> {
     pub const fn local_waker(&self) -> &'a LocalWaker {
         &self.local_waker
     }
+
+    /// Returns a reference to the extension data for the current task.
+    #[inline]
+    #[unstable(feature = "context_ext", issue = "123392")]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    pub const fn ext(&mut self) -> &mut dyn Any {
+        match &mut self.ext {
+            ExtData::Some(data) => *data,
+            ExtData::None(unit) => unit,
+        }
+    }
 }
 
 #[stable(feature = "futures_api", since = "1.36.0")]
@@ -300,6 +320,7 @@ impl fmt::Debug for Context<'_> {
 pub struct ContextBuilder<'a> {
     waker: &'a Waker,
     local_waker: &'a LocalWaker,
+    ext: ExtData<'a>,
     // Ensure we future-proof against variance changes by forcing
     // the lifetime to be invariant (argument-position lifetimes
     // are contravariant while return-position lifetimes are
@@ -318,7 +339,39 @@ impl<'a> ContextBuilder<'a> {
     pub const fn from_waker(waker: &'a Waker) -> Self {
         // SAFETY: LocalWaker is just Waker without thread safety
         let local_waker = unsafe { transmute(waker) };
-        Self { waker: waker, local_waker, _marker: PhantomData, _marker2: PhantomData }
+        Self {
+            waker: waker,
+            local_waker,
+            ext: ExtData::None(()),
+            _marker: PhantomData,
+            _marker2: PhantomData,
+        }
+    }
+
+    /// Create a ContextBuilder from an existing Context.
+    #[inline]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    #[unstable(feature = "context_ext", issue = "123392")]
+    pub const fn from(cx: &'a mut Context<'_>) -> Self {
+        let ext = match &mut cx.ext {
+            ExtData::Some(ext) => ExtData::Some(*ext),
+            ExtData::None(()) => ExtData::None(()),
+        };
+        Self {
+            waker: cx.waker,
+            local_waker: cx.local_waker,
+            ext,
+            _marker: PhantomData,
+            _marker2: PhantomData,
+        }
+    }
+
+    /// This method is used to set the value for the waker on `Context`.
+    #[inline]
+    #[unstable(feature = "context_ext", issue = "123392")]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    pub const fn waker(self, waker: &'a Waker) -> Self {
+        Self { waker, ..self }
     }
 
     /// This method is used to set the value for the local waker on `Context`.
@@ -329,13 +382,21 @@ impl<'a> ContextBuilder<'a> {
         Self { local_waker, ..self }
     }
 
+    /// This method is used to set the value for the extension data on `Context`.
+    #[inline]
+    #[unstable(feature = "context_ext", issue = "123392")]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    pub const fn ext(self, data: &'a mut dyn Any) -> Self {
+        Self { ext: ExtData::Some(data), ..self }
+    }
+
     /// Builds the `Context`.
     #[inline]
     #[unstable(feature = "local_waker", issue = "118959")]
     #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
     pub const fn build(self) -> Context<'a> {
-        let ContextBuilder { waker, local_waker, _marker, _marker2 } = self;
-        Context { waker, local_waker, _marker, _marker2 }
+        let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self;
+        Context { waker, local_waker, ext, _marker, _marker2 }
     }
 }
 
diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs
index 740565d0df6..eb1e1a0b9b1 100644
--- a/library/core/tests/intrinsics.rs
+++ b/library/core/tests/intrinsics.rs
@@ -99,3 +99,30 @@ fn test_const_deallocate_at_runtime() {
         const_deallocate(core::ptr::null_mut(), 1, 1); // nop
     }
 }
+
+#[cfg(not(bootstrap))]
+#[test]
+fn test_three_way_compare_in_const_contexts() {
+    use core::cmp::Ordering::{self, *};
+    use core::intrinsics::three_way_compare;
+
+    const UNSIGNED_LESS: Ordering = three_way_compare(123_u16, 456);
+    const UNSIGNED_EQUAL: Ordering = three_way_compare(456_u16, 456);
+    const UNSIGNED_GREATER: Ordering = three_way_compare(789_u16, 456);
+    const CHAR_LESS: Ordering = three_way_compare('A', 'B');
+    const CHAR_EQUAL: Ordering = three_way_compare('B', 'B');
+    const CHAR_GREATER: Ordering = three_way_compare('C', 'B');
+    const SIGNED_LESS: Ordering = three_way_compare(123_i64, 456);
+    const SIGNED_EQUAL: Ordering = three_way_compare(456_i64, 456);
+    const SIGNED_GREATER: Ordering = three_way_compare(789_i64, 456);
+
+    assert_eq!(UNSIGNED_LESS, Less);
+    assert_eq!(UNSIGNED_EQUAL, Equal);
+    assert_eq!(UNSIGNED_GREATER, Greater);
+    assert_eq!(CHAR_LESS, Less);
+    assert_eq!(CHAR_EQUAL, Equal);
+    assert_eq!(CHAR_GREATER, Greater);
+    assert_eq!(SIGNED_LESS, Less);
+    assert_eq!(SIGNED_EQUAL, Equal);
+    assert_eq!(SIGNED_GREATER, Greater);
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 421062f5873..175c27662d0 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -16,11 +16,13 @@
 #![feature(const_hash)]
 #![feature(const_heap)]
 #![feature(const_intrinsic_copy)]
+#![feature(const_int_from_str)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_nonnull_new)]
 #![feature(const_pointer_is_aligned)]
 #![feature(const_ptr_as_ref)]
 #![feature(const_ptr_write)]
+#![cfg_attr(not(bootstrap), feature(const_three_way_compare))]
 #![feature(const_trait_impl)]
 #![feature(const_likely)]
 #![feature(const_location_fields)]
@@ -95,7 +97,7 @@
 #![feature(const_waker)]
 #![feature(never_type)]
 #![feature(unwrap_infallible)]
-#![feature(pointer_is_aligned)]
+#![feature(pointer_is_aligned_to)]
 #![feature(portable_simd)]
 #![feature(ptr_metadata)]
 #![feature(lazy_cell)]
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 863da9b18a2..0fed854318d 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -214,6 +214,16 @@ fn test_infallible_try_from_int_error() {
     assert!(func(0).is_ok());
 }
 
+const _TEST_CONST_PARSE: () = {
+    let Ok(-0x8000) = i16::from_str_radix("-8000", 16) else { panic!() };
+    let Ok(12345) = u64::from_str_radix("12345", 10) else { panic!() };
+    if let Err(e) = i8::from_str_radix("+", 10) {
+        let IntErrorKind::InvalidDigit = e.kind() else { panic!() };
+    } else {
+        panic!()
+    }
+};
+
 macro_rules! test_impl_from {
     ($fn_name:ident, bool, $target: ty) => {
         #[test]
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 5c518e2d593..f0656f997fd 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -841,12 +841,20 @@ fn ptr_metadata_bounds() {
     fn static_assert_expected_bounds_for_metadata<Meta>()
     where
         // Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs`
-        Meta: Copy + Send + Sync + Ord + std::hash::Hash + Unpin,
+        Meta: Debug + Copy + Send + Sync + Ord + std::hash::Hash + Unpin,
     {
     }
 }
 
 #[test]
+fn pointee_metadata_debug() {
+    assert_eq!("()", format!("{:?}", metadata::<u32>(&17)));
+    assert_eq!("2", format!("{:?}", metadata::<[u32]>(&[19, 23])));
+    let for_dyn = format!("{:?}", metadata::<dyn Debug>(&29));
+    assert!(for_dyn.starts_with("DynMetadata(0x"), "{:?}", for_dyn);
+}
+
+#[test]
 fn dyn_metadata() {
     #[derive(Debug)]
     #[repr(align(32))]
diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs
index e217d1c8c87..0f1719206c9 100644
--- a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs
@@ -50,14 +50,14 @@ pub trait SimdConstPtr: Copy + Sealed {
     /// Equivalent to calling [`pointer::with_addr`] on each element.
     fn with_addr(self, addr: Self::Usize) -> Self;
 
-    /// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use
-    /// in [`Self::from_exposed_addr`].
-    fn expose_addr(self) -> Self::Usize;
+    /// Exposes the "provenance" part of the pointer for future use in
+    /// [`Self::with_exposed_provenance`] and returns the "address" portion.
+    fn expose_provenance(self) -> Self::Usize;
 
     /// Convert an address back to a pointer, picking up a previously "exposed" provenance.
     ///
-    /// Equivalent to calling [`core::ptr::from_exposed_addr`] on each element.
-    fn from_exposed_addr(addr: Self::Usize) -> Self;
+    /// Equivalent to calling [`core::ptr::with_exposed_provenance`] on each element.
+    fn with_exposed_provenance(addr: Self::Usize) -> Self;
 
     /// Calculates the offset from a pointer using wrapping arithmetic.
     ///
@@ -131,15 +131,15 @@ where
     }
 
     #[inline]
-    fn expose_addr(self) -> Self::Usize {
+    fn expose_provenance(self) -> Self::Usize {
         // Safety: `self` is a pointer vector
-        unsafe { core::intrinsics::simd::simd_expose_addr(self) }
+        unsafe { core::intrinsics::simd::simd_expose_provenance(self) }
     }
 
     #[inline]
-    fn from_exposed_addr(addr: Self::Usize) -> Self {
+    fn with_exposed_provenance(addr: Self::Usize) -> Self {
         // Safety: `self` is a pointer vector
-        unsafe { core::intrinsics::simd::simd_from_exposed_addr(addr) }
+        unsafe { core::intrinsics::simd::simd_with_exposed_provenance(addr) }
     }
 
     #[inline]
diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs
index 5cb27af4fde..7ba996d149c 100644
--- a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs
@@ -47,14 +47,14 @@ pub trait SimdMutPtr: Copy + Sealed {
     /// Equivalent to calling [`pointer::with_addr`] on each element.
     fn with_addr(self, addr: Self::Usize) -> Self;
 
-    /// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use
-    /// in [`Self::from_exposed_addr`].
-    fn expose_addr(self) -> Self::Usize;
+    /// Exposes the "provenance" part of the pointer for future use in
+    /// [`Self::with_exposed_provenance`] and returns the "address" portion.
+    fn expose_provenance(self) -> Self::Usize;
 
     /// Convert an address back to a pointer, picking up a previously "exposed" provenance.
     ///
-    /// Equivalent to calling [`core::ptr::from_exposed_addr_mut`] on each element.
-    fn from_exposed_addr(addr: Self::Usize) -> Self;
+    /// Equivalent to calling [`core::ptr::with_exposed_provenance_mut`] on each element.
+    fn with_exposed_provenance(addr: Self::Usize) -> Self;
 
     /// Calculates the offset from a pointer using wrapping arithmetic.
     ///
@@ -128,15 +128,15 @@ where
     }
 
     #[inline]
-    fn expose_addr(self) -> Self::Usize {
+    fn expose_provenance(self) -> Self::Usize {
         // Safety: `self` is a pointer vector
-        unsafe { core::intrinsics::simd::simd_expose_addr(self) }
+        unsafe { core::intrinsics::simd::simd_expose_provenance(self) }
     }
 
     #[inline]
-    fn from_exposed_addr(addr: Self::Usize) -> Self {
+    fn with_exposed_provenance(addr: Self::Usize) -> Self {
         // Safety: `self` is a pointer vector
-        unsafe { core::intrinsics::simd::simd_from_exposed_addr(addr) }
+        unsafe { core::intrinsics::simd::simd_with_exposed_provenance(addr) }
     }
 
     #[inline]
diff --git a/library/portable-simd/crates/core_simd/tests/pointers.rs b/library/portable-simd/crates/core_simd/tests/pointers.rs
index b9f32d16e01..90bfc5d5fd6 100644
--- a/library/portable-simd/crates/core_simd/tests/pointers.rs
+++ b/library/portable-simd/crates/core_simd/tests/pointers.rs
@@ -32,10 +32,10 @@ macro_rules! common_tests {
                 );
             }
 
-            fn expose_addr<const LANES: usize>() {
+            fn expose_provenance<const LANES: usize>() {
                 test_helpers::test_unary_elementwise(
-                    &Simd::<*$constness u32, LANES>::expose_addr,
-                    &<*$constness u32>::expose_addr,
+                    &Simd::<*$constness u32, LANES>::expose_provenance,
+                    &<*$constness u32>::expose_provenance,
                     &|_| true,
                 );
             }
@@ -80,10 +80,10 @@ mod const_ptr {
             );
         }
 
-        fn from_exposed_addr<const LANES: usize>() {
+        fn with_exposed_provenance<const LANES: usize>() {
             test_helpers::test_unary_elementwise(
-                &Simd::<*const u32, LANES>::from_exposed_addr,
-                &core::ptr::from_exposed_addr::<u32>,
+                &Simd::<*const u32, LANES>::with_exposed_provenance,
+                &core::ptr::with_exposed_provenance::<u32>,
                 &|_| true,
             );
         }
@@ -103,10 +103,10 @@ mod mut_ptr {
             );
         }
 
-        fn from_exposed_addr<const LANES: usize>() {
+        fn with_exposed_provenance<const LANES: usize>() {
             test_helpers::test_unary_elementwise(
-                &Simd::<*mut u32, LANES>::from_exposed_addr,
-                &core::ptr::from_exposed_addr_mut::<u32>,
+                &Simd::<*mut u32, LANES>::with_exposed_provenance,
+                &core::ptr::with_exposed_provenance_mut::<u32>,
                 &|_| true,
             );
         }
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 9017ba79714..b1102b440e0 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -37,7 +37,7 @@ use crate::time::SystemTime;
 ///
 /// # Examples
 ///
-/// Creates a new file and write bytes to it (you can also use [`write()`]):
+/// Creates a new file and write bytes to it (you can also use [`write`]):
 ///
 /// ```no_run
 /// use std::fs::File;
@@ -2018,7 +2018,7 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
 /// the length of the `to` file as reported by `metadata`.
 ///
 /// If you want to copy the contents of one file to another and you’re
-/// working with [`File`]s, see the [`io::copy()`] function.
+/// working with [`File`]s, see the [`io::copy`](io::copy()) function.
 ///
 /// # Platform-specific behavior
 ///
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 3781ae15c3a..31a8711e0eb 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -341,7 +341,7 @@
 #![feature(panic_can_unwind)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
-#![feature(pointer_is_aligned)]
+#![feature(pointer_is_aligned_to)]
 #![feature(portable_simd)]
 #![feature(prelude_2024)]
 #![feature(ptr_as_uninit)]
diff --git a/library/std/src/os/xous/ffi.rs b/library/std/src/os/xous/ffi.rs
index 7fe84db515c..e9a9f533720 100644
--- a/library/std/src/os/xous/ffi.rs
+++ b/library/std/src/os/xous/ffi.rs
@@ -389,7 +389,7 @@ pub(crate) unsafe fn map_memory<T>(
     let result = a0;
 
     if result == SyscallResult::MemoryRange as usize {
-        let start = core::ptr::from_exposed_addr_mut::<T>(a1);
+        let start = core::ptr::with_exposed_provenance_mut::<T>(a1);
         let len = a2 / core::mem::size_of::<T>();
         let end = unsafe { start.add(len) };
         Ok(unsafe { core::slice::from_raw_parts_mut(start, len) })
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 3d576af681e..e63b46ab705 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -126,6 +126,9 @@ where
 /// Also note that unwinding into Rust code with a foreign exception (e.g.
 /// an exception thrown from C++ code) is undefined behavior.
 ///
+/// Finally, be **careful in how you drop the result of this function**.
+/// If it is `Err`, it contains the panic payload, and dropping that may in turn panic!
+///
 /// # Examples
 ///
 /// ```
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 31dbe86b66c..f46e1e171d2 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -21,7 +21,6 @@ use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sync::{PoisonError, RwLock};
 use crate::sys::stdio::panic_output;
 use crate::sys_common::backtrace;
-use crate::sys_common::thread_info;
 use crate::thread;
 
 #[cfg(not(test))]
@@ -256,7 +255,7 @@ fn default_hook(info: &PanicInfo<'_>) {
             None => "Box<dyn Any>",
         },
     };
-    let thread = thread_info::current_thread();
+    let thread = thread::try_current();
     let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
 
     let write = |err: &mut dyn crate::io::Write| {
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 335944845ae..ff6e433ebce 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -24,8 +24,7 @@ pub use core::panicking::{panic_display, panic_fmt};
 
 use crate::sync::Once;
 use crate::sys;
-use crate::sys_common::thread_info;
-use crate::thread::Thread;
+use crate::thread::{self, Thread};
 
 // Prints to the "panic output", depending on the platform this may be:
 // - the standard error output
@@ -96,13 +95,9 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     unsafe {
         sys::init(argc, argv, sigpipe);
 
-        let main_guard = sys::thread::guard::init();
-        // Next, set up the current Thread with the guard information we just
-        // created. Note that this isn't necessary in general for new threads,
-        // but we just do this to name the main thread and to give it correct
-        // info about the stack bounds.
+        // Set up the current thread to give it the right name.
         let thread = Thread::new(Some(rtunwrap!(Ok, CString::new("main"))));
-        thread_info::set(main_guard, thread);
+        thread::set_current(thread);
     }
 }
 
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index cf45b9c2396..40f88e33d4a 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -29,7 +29,7 @@ impl Thread {
         let p = Box::into_raw(Box::new(p));
         let tid = abi::spawn2(
             thread_start,
-            p.expose_addr(),
+            p.expose_provenance(),
             abi::Priority::into(abi::NORMAL_PRIO),
             stack,
             core_id,
@@ -47,7 +47,7 @@ impl Thread {
         extern "C" fn thread_start(main: usize) {
             unsafe {
                 // Finally, let's run some code.
-                Box::from_raw(ptr::from_exposed_addr::<Box<dyn FnOnce()>>(main).cast_mut())();
+                Box::from_raw(ptr::with_exposed_provenance::<Box<dyn FnOnce()>>(main).cast_mut())();
 
                 // run all destructors
                 run_dtors();
@@ -104,13 +104,3 @@ impl Thread {
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsafe { Ok(NonZero::new_unchecked(abi::get_processor_count())) }
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs
index 814a102dd09..047513a6792 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/pal/itron/thread.rs
@@ -98,7 +98,7 @@ impl Thread {
         });
 
         unsafe extern "C" fn trampoline(exinf: isize) {
-            let p_inner: *mut ThreadInner = crate::ptr::from_exposed_addr_mut(exinf as usize);
+            let p_inner: *mut ThreadInner = crate::ptr::with_exposed_provenance_mut(exinf as usize);
             // Safety: `ThreadInner` is alive at this point
             let inner = unsafe { &*p_inner };
 
@@ -181,7 +181,7 @@ impl Thread {
             abi::acre_tsk(&abi::T_CTSK {
                 // Activate this task immediately
                 tskatr: abi::TA_ACT,
-                exinf: p_inner.as_ptr().expose_addr() as abi::EXINF,
+                exinf: p_inner.as_ptr().expose_provenance() as abi::EXINF,
                 // The entry point
                 task: Some(trampoline),
                 // Inherit the calling task's base priority
@@ -312,16 +312,6 @@ impl Drop for Thread {
     }
 }
 
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
-
 /// Terminate and delete the specified task.
 ///
 /// This function will abort if `deleted_task` refers to the calling task.
diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs
index 7c87deed371..8c75ac65299 100644
--- a/library/std/src/sys/pal/mod.rs
+++ b/library/std/src/sys/pal/mod.rs
@@ -37,12 +37,12 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_os = "hermit")] {
         mod hermit;
         pub use self::hermit::*;
-    } else if #[cfg(target_os = "wasi")] {
-        mod wasi;
-        pub use self::wasi::*;
     } else if #[cfg(all(target_os = "wasi", target_env = "p2"))] {
         mod wasip2;
         pub use self::wasip2::*;
+    } else if #[cfg(target_os = "wasi")] {
+        mod wasi;
+        pub use self::wasi::*;
     } else if #[cfg(target_family = "wasm")] {
         mod wasm;
         pub use self::wasm::*;
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs
index 77f68bf7334..ef07f6e6a26 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/pal/sgx/thread.rs
@@ -149,13 +149,3 @@ impl Thread {
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs
index b76bcf9bbb0..fb4b74ba3c3 100644
--- a/library/std/src/sys/pal/teeos/thread.rs
+++ b/library/std/src/sys/pal/teeos/thread.rs
@@ -151,18 +151,6 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     ))
 }
 
-// stub
-pub mod guard {
-    use crate::ops::Range;
-    pub type Guard = Range<usize>;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
-
 fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
     libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
 }
diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs
index b3a4f9c53e3..ca7b1efc269 100644
--- a/library/std/src/sys/pal/uefi/thread.rs
+++ b/library/std/src/sys/pal/uefi/thread.rs
@@ -52,13 +52,3 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // UEFI is single threaded
     Ok(NonZero::new(1).unwrap())
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs
index c9ed6825f6c..d52c3254e5e 100644
--- a/library/std/src/sys/pal/unix/rand.rs
+++ b/library/std/src/sys/pal/unix/rand.rs
@@ -62,17 +62,23 @@ mod imp {
         unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) }
     }
 
-    #[cfg(any(
-        target_os = "espidf",
-        target_os = "horizon",
-        target_os = "freebsd",
-        target_os = "dragonfly",
-        netbsd10
-    ))]
+    #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "freebsd", netbsd10))]
     fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
         unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }
     }
 
+    #[cfg(target_os = "dragonfly")]
+    fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
+        extern "C" {
+            fn getrandom(
+                buf: *mut libc::c_void,
+                buflen: libc::size_t,
+                flags: libc::c_uint,
+            ) -> libc::ssize_t;
+        }
+        unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }
+    }
+
     #[cfg(not(any(
         target_os = "linux",
         target_os = "android",
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index 78a599077c7..26c49257ad0 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -11,7 +11,7 @@ pub struct Handler {
 
 impl Handler {
     pub unsafe fn new() -> Handler {
-        make_handler()
+        make_handler(false)
     }
 
     fn null() -> Handler {
@@ -29,34 +29,41 @@ impl Drop for Handler {
 
 #[cfg(any(
     target_os = "linux",
-    target_os = "macos",
-    target_os = "dragonfly",
     target_os = "freebsd",
     target_os = "hurd",
-    target_os = "solaris",
-    target_os = "illumos",
+    target_os = "macos",
     target_os = "netbsd",
-    target_os = "openbsd"
+    target_os = "openbsd",
+    target_os = "solaris"
 ))]
 mod imp {
     use super::Handler;
+    use crate::cell::Cell;
     use crate::io;
     use crate::mem;
+    use crate::ops::Range;
     use crate::ptr;
+    use crate::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
+    use crate::sys::pal::unix::os;
     use crate::thread;
 
-    use libc::MAP_FAILED;
     #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
-    use libc::{mmap as mmap64, munmap};
+    use libc::{mmap as mmap64, mprotect, munmap};
     #[cfg(all(target_os = "linux", target_env = "gnu"))]
-    use libc::{mmap64, munmap};
-    use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
+    use libc::{mmap64, mprotect, munmap};
+    use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIGSEGV, SIG_DFL};
     use libc::{sigaltstack, SS_DISABLE};
-    use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};
+    use libc::{MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
 
-    use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
-    use crate::sys::pal::unix::os::page_size;
-    use crate::sys_common::thread_info;
+    // We use a TLS variable to store the address of the guard page. While TLS
+    // variables are not guaranteed to be signal-safe, this works out in practice
+    // since we make sure to write to the variable before the signal stack is
+    // installed, thereby ensuring that the variable is always allocated when
+    // the signal handler is called.
+    thread_local! {
+        // FIXME: use `Range` once that implements `Copy`.
+        static GUARD: Cell<(usize, usize)> = const { Cell::new((0, 0)) };
+    }
 
     // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
     // (unmapped pages) at the end of every thread's stack, so if a thread ends
@@ -84,12 +91,12 @@ mod imp {
         info: *mut libc::siginfo_t,
         _data: *mut libc::c_void,
     ) {
-        let guard = thread_info::stack_guard().unwrap_or(0..0);
+        let (start, end) = GUARD.get();
         let addr = (*info).si_addr() as usize;
 
         // If the faulting address is within the guard page, then we print a
         // message saying so and abort.
-        if guard.start <= addr && addr < guard.end {
+        if start <= addr && addr < end {
             rtprintpanic!(
                 "\nthread '{}' has overflowed its stack\n",
                 thread::current().name().unwrap_or("<unknown>")
@@ -105,10 +112,17 @@ mod imp {
         }
     }
 
+    static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
     static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut());
     static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false);
 
     pub unsafe fn init() {
+        PAGE_SIZE.store(os::page_size(), Ordering::Relaxed);
+
+        // Always write to GUARD to ensure the TLS variable is allocated.
+        let guard = install_main_guard().unwrap_or(0..0);
+        GUARD.set((guard.start, guard.end));
+
         let mut action: sigaction = mem::zeroed();
         for &signal in &[SIGSEGV, SIGBUS] {
             sigaction(signal, ptr::null_mut(), &mut action);
@@ -121,7 +135,7 @@ mod imp {
             }
         }
 
-        let handler = make_handler();
+        let handler = make_handler(true);
         MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
         mem::forget(handler);
     }
@@ -150,7 +164,7 @@ mod imp {
         let flags = MAP_PRIVATE | MAP_ANON;
 
         let sigstack_size = sigstack_size();
-        let page_size = page_size();
+        let page_size = PAGE_SIZE.load(Ordering::Relaxed);
 
         let stackp = mmap64(
             ptr::null_mut(),
@@ -172,10 +186,17 @@ mod imp {
         libc::stack_t { ss_sp: stackp, ss_flags: 0, ss_size: sigstack_size }
     }
 
-    pub unsafe fn make_handler() -> Handler {
+    pub unsafe fn make_handler(main_thread: bool) -> Handler {
         if !NEED_ALTSTACK.load(Ordering::Relaxed) {
             return Handler::null();
         }
+
+        if !main_thread {
+            // Always write to GUARD to ensure the TLS variable is allocated.
+            let guard = current_guard().unwrap_or(0..0);
+            GUARD.set((guard.start, guard.end));
+        }
+
         let mut stack = mem::zeroed();
         sigaltstack(ptr::null(), &mut stack);
         // Configure alternate signal stack, if one is not already set.
@@ -191,7 +212,7 @@ mod imp {
     pub unsafe fn drop_handler(data: *mut libc::c_void) {
         if !data.is_null() {
             let sigstack_size = sigstack_size();
-            let page_size = page_size();
+            let page_size = PAGE_SIZE.load(Ordering::Relaxed);
             let stack = libc::stack_t {
                 ss_sp: ptr::null_mut(),
                 ss_flags: SS_DISABLE,
@@ -225,25 +246,266 @@ mod imp {
     fn sigstack_size() -> usize {
         libc::SIGSTKSZ
     }
+
+    #[cfg(target_os = "solaris")]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let mut current_stack: libc::stack_t = crate::mem::zeroed();
+        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
+        Some(current_stack.ss_sp)
+    }
+
+    #[cfg(target_os = "macos")]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let th = libc::pthread_self();
+        let stackptr = libc::pthread_get_stackaddr_np(th);
+        Some(stackptr.map_addr(|addr| addr - libc::pthread_get_stacksize_np(th)))
+    }
+
+    #[cfg(target_os = "openbsd")]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let mut current_stack: libc::stack_t = crate::mem::zeroed();
+        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), &mut current_stack), 0);
+
+        let stack_ptr = current_stack.ss_sp;
+        let stackaddr = if libc::pthread_main_np() == 1 {
+            // main thread
+            stack_ptr.addr() - current_stack.ss_size + PAGE_SIZE.load(Ordering::Relaxed)
+        } else {
+            // new thread
+            stack_ptr.addr() - current_stack.ss_size
+        };
+        Some(stack_ptr.with_addr(stackaddr))
+    }
+
+    #[cfg(any(
+        target_os = "android",
+        target_os = "freebsd",
+        target_os = "netbsd",
+        target_os = "hurd",
+        target_os = "linux",
+        target_os = "l4re"
+    ))]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let mut ret = None;
+        let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
+        #[cfg(target_os = "freebsd")]
+        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+        #[cfg(target_os = "freebsd")]
+        let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
+        #[cfg(not(target_os = "freebsd"))]
+        let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
+        if e == 0 {
+            let mut stackaddr = crate::ptr::null_mut();
+            let mut stacksize = 0;
+            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
+            ret = Some(stackaddr);
+        }
+        if e == 0 || cfg!(target_os = "freebsd") {
+            assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+        }
+        ret
+    }
+
+    unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
+        let page_size = PAGE_SIZE.load(Ordering::Relaxed);
+        let stackptr = get_stack_start()?;
+        let stackaddr = stackptr.addr();
+
+        // Ensure stackaddr is page aligned! A parent process might
+        // have reset RLIMIT_STACK to be non-page aligned. The
+        // pthread_attr_getstack() reports the usable stack area
+        // stackaddr < stackaddr + stacksize, so if stackaddr is not
+        // page-aligned, calculate the fix such that stackaddr <
+        // new_page_aligned_stackaddr < stackaddr + stacksize
+        let remainder = stackaddr % page_size;
+        Some(if remainder == 0 {
+            stackptr
+        } else {
+            stackptr.with_addr(stackaddr + page_size - remainder)
+        })
+    }
+
+    unsafe fn install_main_guard() -> Option<Range<usize>> {
+        let page_size = PAGE_SIZE.load(Ordering::Relaxed);
+        if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
+            // Linux doesn't allocate the whole stack right away, and
+            // the kernel has its own stack-guard mechanism to fault
+            // when growing too close to an existing mapping. If we map
+            // our own guard, then the kernel starts enforcing a rather
+            // large gap above that, rendering much of the possible
+            // stack space useless. See #43052.
+            //
+            // Instead, we'll just note where we expect rlimit to start
+            // faulting, so our handler can report "stack overflow", and
+            // trust that the kernel's own stack guard will work.
+            let stackptr = get_stack_start_aligned()?;
+            let stackaddr = stackptr.addr();
+            Some(stackaddr - page_size..stackaddr)
+        } else if cfg!(all(target_os = "linux", target_env = "musl")) {
+            // For the main thread, the musl's pthread_attr_getstack
+            // returns the current stack size, rather than maximum size
+            // it can eventually grow to. It cannot be used to determine
+            // the position of kernel's stack guard.
+            None
+        } else if cfg!(target_os = "freebsd") {
+            // FreeBSD's stack autogrows, and optionally includes a guard page
+            // at the bottom. If we try to remap the bottom of the stack
+            // ourselves, FreeBSD's guard page moves upwards. So we'll just use
+            // the builtin guard page.
+            let stackptr = get_stack_start_aligned()?;
+            let guardaddr = stackptr.addr();
+            // Technically the number of guard pages is tunable and controlled
+            // by the security.bsd.stack_guard_page sysctl.
+            // By default it is 1, checking once is enough since it is
+            // a boot time config value.
+            static PAGES: crate::sync::OnceLock<usize> = crate::sync::OnceLock::new();
+
+            let pages = PAGES.get_or_init(|| {
+                use crate::sys::weak::dlsym;
+                dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int);
+                let mut guard: usize = 0;
+                let mut size = crate::mem::size_of_val(&guard);
+                let oid = crate::ffi::CStr::from_bytes_with_nul(
+                    b"security.bsd.stack_guard_page\0",
+                )
+                .unwrap();
+                match sysctlbyname.get() {
+                    Some(fcn) => {
+                        if fcn(oid.as_ptr(), core::ptr::addr_of_mut!(guard) as *mut _, core::ptr::addr_of_mut!(size) as *mut _, crate::ptr::null_mut(), 0) == 0 {
+                            guard
+                        } else {
+                            1
+                        }
+                    },
+                    _ => 1,
+                }
+            });
+            Some(guardaddr..guardaddr + pages * page_size)
+        } else if cfg!(any(target_os = "openbsd", target_os = "netbsd")) {
+            // OpenBSD stack already includes a guard page, and stack is
+            // immutable.
+            // NetBSD stack includes the guard page.
+            //
+            // We'll just note where we expect rlimit to start
+            // faulting, so our handler can report "stack overflow", and
+            // trust that the kernel's own stack guard will work.
+            let stackptr = get_stack_start_aligned()?;
+            let stackaddr = stackptr.addr();
+            Some(stackaddr - page_size..stackaddr)
+        } else {
+            // Reallocate the last page of the stack.
+            // This ensures SIGBUS will be raised on
+            // stack overflow.
+            // Systems which enforce strict PAX MPROTECT do not allow
+            // to mprotect() a mapping with less restrictive permissions
+            // than the initial mmap() used, so we mmap() here with
+            // read/write permissions and only then mprotect() it to
+            // no permissions at all. See issue #50313.
+            let stackptr = get_stack_start_aligned()?;
+            let result = mmap64(
+                stackptr,
+                page_size,
+                PROT_READ | PROT_WRITE,
+                MAP_PRIVATE | MAP_ANON | MAP_FIXED,
+                -1,
+                0,
+            );
+            if result != stackptr || result == MAP_FAILED {
+                panic!("failed to allocate a guard page: {}", io::Error::last_os_error());
+            }
+
+            let result = mprotect(stackptr, page_size, PROT_NONE);
+            if result != 0 {
+                panic!("failed to protect the guard page: {}", io::Error::last_os_error());
+            }
+
+            let guardaddr = stackptr.addr();
+
+            Some(guardaddr..guardaddr + page_size)
+        }
+    }
+
+    #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]
+    unsafe fn current_guard() -> Option<Range<usize>> {
+        let stackptr = get_stack_start()?;
+        let stackaddr = stackptr.addr();
+        Some(stackaddr - PAGE_SIZE.load(Ordering::Relaxed)..stackaddr)
+    }
+
+    #[cfg(any(
+        target_os = "android",
+        target_os = "freebsd",
+        target_os = "hurd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "l4re"
+    ))]
+    unsafe fn current_guard() -> Option<Range<usize>> {
+        let mut ret = None;
+        let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
+        #[cfg(target_os = "freebsd")]
+        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+        #[cfg(target_os = "freebsd")]
+        let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
+        #[cfg(not(target_os = "freebsd"))]
+        let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
+        if e == 0 {
+            let mut guardsize = 0;
+            assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0);
+            if guardsize == 0 {
+                if cfg!(all(target_os = "linux", target_env = "musl")) {
+                    // musl versions before 1.1.19 always reported guard
+                    // size obtained from pthread_attr_get_np as zero.
+                    // Use page size as a fallback.
+                    guardsize = PAGE_SIZE.load(Ordering::Relaxed);
+                } else {
+                    panic!("there is no guard page");
+                }
+            }
+            let mut stackptr = crate::ptr::null_mut::<libc::c_void>();
+            let mut size = 0;
+            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackptr, &mut size), 0);
+
+            let stackaddr = stackptr.addr();
+            ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "hurd")) {
+                Some(stackaddr - guardsize..stackaddr)
+            } else if cfg!(all(target_os = "linux", target_env = "musl")) {
+                Some(stackaddr - guardsize..stackaddr)
+            } else if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))
+            {
+                // glibc used to include the guard area within the stack, as noted in the BUGS
+                // section of `man pthread_attr_getguardsize`. This has been corrected starting
+                // with glibc 2.27, and in some distro backports, so the guard is now placed at the
+                // end (below) the stack. There's no easy way for us to know which we have at
+                // runtime, so we'll just match any fault in the range right above or below the
+                // stack base to call that fault a stack overflow.
+                Some(stackaddr - guardsize..stackaddr + guardsize)
+            } else {
+                Some(stackaddr..stackaddr + guardsize)
+            };
+        }
+        if e == 0 || cfg!(target_os = "freebsd") {
+            assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+        }
+        ret
+    }
 }
 
 #[cfg(not(any(
     target_os = "linux",
-    target_os = "macos",
-    target_os = "dragonfly",
     target_os = "freebsd",
     target_os = "hurd",
-    target_os = "solaris",
-    target_os = "illumos",
+    target_os = "macos",
     target_os = "netbsd",
     target_os = "openbsd",
+    target_os = "solaris"
 )))]
 mod imp {
     pub unsafe fn init() {}
 
     pub unsafe fn cleanup() {}
 
-    pub unsafe fn make_handler() -> super::Handler {
+    pub unsafe fn make_handler(_main_thread: bool) -> super::Handler {
         super::Handler::null()
     }
 
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 4cd7c0e3059..7d25c974ed3 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -182,8 +182,11 @@ impl Thread {
 
         if let Some(f) = pthread_setname_np.get() {
             #[cfg(target_os = "nto")]
-            let name = truncate_cstr::<{ libc::_NTO_THREAD_NAME_MAX as usize }>(name);
+            const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize;
+            #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+            const THREAD_NAME_MAX: usize = 32;
 
+            let name = truncate_cstr::<{ THREAD_NAME_MAX }>(name);
             let res = unsafe { f(libc::pthread_self(), name.as_ptr()) };
             debug_assert_eq!(res, 0);
         }
@@ -225,9 +228,20 @@ impl Thread {
         // Newlib, Emscripten, and VxWorks have no way to set a thread name.
     }
 
-    #[cfg(target_os = "linux")]
+    #[cfg(any(
+        target_os = "linux",
+        target_os = "freebsd",
+        target_os = "netbsd",
+        target_os = "solaris",
+        target_os = "illumos"
+    ))]
     pub fn get_name() -> Option<CString> {
+        #[cfg(target_os = "linux")]
         const TASK_COMM_LEN: usize = 16;
+        #[cfg(target_os = "freebsd")]
+        const TASK_COMM_LEN: usize = libc::MAXCOMLEN + 1;
+        #[cfg(any(target_os = "netbsd", target_os = "solaris", target_os = "illumos"))]
+        const TASK_COMM_LEN: usize = 32;
         let mut name = vec![0u8; TASK_COMM_LEN];
         let res = unsafe {
             libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len())
@@ -252,12 +266,35 @@ impl Thread {
         CString::new(name).ok()
     }
 
+    #[cfg(target_os = "haiku")]
+    pub fn get_name() -> Option<CString> {
+        unsafe {
+            let mut tinfo = mem::MaybeUninit::<libc::thread_info>::uninit();
+            // See BeOS teams group and threads api.
+            // https://www.haiku-os.org/legacy-docs/bebook/TheKernelKit_ThreadsAndTeams_Overview.html
+            let thread_self = libc::find_thread(ptr::null_mut());
+            let res = libc::get_thread_info(thread_self, tinfo.as_mut_ptr());
+            if res != libc::B_OK {
+                return None;
+            }
+            let info = tinfo.assume_init();
+            let name =
+                core::slice::from_raw_parts(info.name.as_ptr() as *const u8, info.name.len());
+            CStr::from_bytes_until_nul(name).map(CStr::to_owned).ok()
+        }
+    }
+
     #[cfg(not(any(
         target_os = "linux",
+        target_os = "freebsd",
+        target_os = "netbsd",
         target_os = "macos",
         target_os = "ios",
         target_os = "tvos",
-        target_os = "watchos"
+        target_os = "watchos",
+        target_os = "haiku",
+        target_os = "solaris",
+        target_os = "illumos"
     )))]
     pub fn get_name() -> Option<CString> {
         None
@@ -335,6 +372,8 @@ impl Drop for Thread {
     target_os = "tvos",
     target_os = "watchos",
     target_os = "nto",
+    target_os = "solaris",
+    target_os = "illumos",
 ))]
 fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
     let mut result = [0; MAX_WITH_NUL];
@@ -729,302 +768,6 @@ mod cgroups {
     }
 }
 
-#[cfg(all(
-    not(target_os = "linux"),
-    not(target_os = "freebsd"),
-    not(target_os = "hurd"),
-    not(target_os = "macos"),
-    not(target_os = "netbsd"),
-    not(target_os = "openbsd"),
-    not(target_os = "solaris")
-))]
-#[cfg_attr(test, allow(dead_code))]
-pub mod guard {
-    use crate::ops::Range;
-    pub type Guard = Range<usize>;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
-
-#[cfg(any(
-    target_os = "linux",
-    target_os = "freebsd",
-    target_os = "hurd",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd",
-    target_os = "solaris"
-))]
-#[cfg_attr(test, allow(dead_code))]
-pub mod guard {
-    #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
-    use libc::{mmap as mmap64, mprotect};
-    #[cfg(all(target_os = "linux", target_env = "gnu"))]
-    use libc::{mmap64, mprotect};
-    use libc::{MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
-
-    use crate::io;
-    use crate::ops::Range;
-    use crate::sync::atomic::{AtomicUsize, Ordering};
-    use crate::sys::os;
-
-    // This is initialized in init() and only read from after
-    static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
-
-    pub type Guard = Range<usize>;
-
-    #[cfg(target_os = "solaris")]
-    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
-        let mut current_stack: libc::stack_t = crate::mem::zeroed();
-        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
-        Some(current_stack.ss_sp)
-    }
-
-    #[cfg(target_os = "macos")]
-    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
-        let th = libc::pthread_self();
-        let stackptr = libc::pthread_get_stackaddr_np(th);
-        Some(stackptr.map_addr(|addr| addr - libc::pthread_get_stacksize_np(th)))
-    }
-
-    #[cfg(target_os = "openbsd")]
-    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
-        let mut current_stack: libc::stack_t = crate::mem::zeroed();
-        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), &mut current_stack), 0);
-
-        let stack_ptr = current_stack.ss_sp;
-        let stackaddr = if libc::pthread_main_np() == 1 {
-            // main thread
-            stack_ptr.addr() - current_stack.ss_size + PAGE_SIZE.load(Ordering::Relaxed)
-        } else {
-            // new thread
-            stack_ptr.addr() - current_stack.ss_size
-        };
-        Some(stack_ptr.with_addr(stackaddr))
-    }
-
-    #[cfg(any(
-        target_os = "android",
-        target_os = "freebsd",
-        target_os = "netbsd",
-        target_os = "hurd",
-        target_os = "linux",
-        target_os = "l4re"
-    ))]
-    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
-        let mut ret = None;
-        let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
-        #[cfg(target_os = "freebsd")]
-        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
-        #[cfg(target_os = "freebsd")]
-        let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
-        #[cfg(not(target_os = "freebsd"))]
-        let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
-        if e == 0 {
-            let mut stackaddr = crate::ptr::null_mut();
-            let mut stacksize = 0;
-            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
-            ret = Some(stackaddr);
-        }
-        if e == 0 || cfg!(target_os = "freebsd") {
-            assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
-        }
-        ret
-    }
-
-    // Precondition: PAGE_SIZE is initialized.
-    unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
-        let page_size = PAGE_SIZE.load(Ordering::Relaxed);
-        assert!(page_size != 0);
-        let stackptr = get_stack_start()?;
-        let stackaddr = stackptr.addr();
-
-        // Ensure stackaddr is page aligned! A parent process might
-        // have reset RLIMIT_STACK to be non-page aligned. The
-        // pthread_attr_getstack() reports the usable stack area
-        // stackaddr < stackaddr + stacksize, so if stackaddr is not
-        // page-aligned, calculate the fix such that stackaddr <
-        // new_page_aligned_stackaddr < stackaddr + stacksize
-        let remainder = stackaddr % page_size;
-        Some(if remainder == 0 {
-            stackptr
-        } else {
-            stackptr.with_addr(stackaddr + page_size - remainder)
-        })
-    }
-
-    pub unsafe fn init() -> Option<Guard> {
-        let page_size = os::page_size();
-        PAGE_SIZE.store(page_size, Ordering::Relaxed);
-
-        if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
-            // Linux doesn't allocate the whole stack right away, and
-            // the kernel has its own stack-guard mechanism to fault
-            // when growing too close to an existing mapping. If we map
-            // our own guard, then the kernel starts enforcing a rather
-            // large gap above that, rendering much of the possible
-            // stack space useless. See #43052.
-            //
-            // Instead, we'll just note where we expect rlimit to start
-            // faulting, so our handler can report "stack overflow", and
-            // trust that the kernel's own stack guard will work.
-            let stackptr = get_stack_start_aligned()?;
-            let stackaddr = stackptr.addr();
-            Some(stackaddr - page_size..stackaddr)
-        } else if cfg!(all(target_os = "linux", target_env = "musl")) {
-            // For the main thread, the musl's pthread_attr_getstack
-            // returns the current stack size, rather than maximum size
-            // it can eventually grow to. It cannot be used to determine
-            // the position of kernel's stack guard.
-            None
-        } else if cfg!(target_os = "freebsd") {
-            // FreeBSD's stack autogrows, and optionally includes a guard page
-            // at the bottom. If we try to remap the bottom of the stack
-            // ourselves, FreeBSD's guard page moves upwards. So we'll just use
-            // the builtin guard page.
-            let stackptr = get_stack_start_aligned()?;
-            let guardaddr = stackptr.addr();
-            // Technically the number of guard pages is tunable and controlled
-            // by the security.bsd.stack_guard_page sysctl.
-            // By default it is 1, checking once is enough since it is
-            // a boot time config value.
-            static LOCK: crate::sync::OnceLock<usize> = crate::sync::OnceLock::new();
-            let guard = guardaddr
-                ..guardaddr
-                    + *LOCK.get_or_init(|| {
-                        use crate::sys::weak::dlsym;
-                        dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int);
-                        let mut guard: usize = 0;
-                        let mut size = crate::mem::size_of_val(&guard);
-                        let oid = crate::ffi::CStr::from_bytes_with_nul(
-                            b"security.bsd.stack_guard_page\0",
-                        )
-                        .unwrap();
-                        match sysctlbyname.get() {
-                            Some(fcn) => {
-                                if fcn(oid.as_ptr(), core::ptr::addr_of_mut!(guard) as *mut _, core::ptr::addr_of_mut!(size) as *mut _, crate::ptr::null_mut(), 0) == 0 {
-                                    return guard;
-                                }
-                                return 1;
-                            },
-                            _ => { return 1; }
-                        }
-                    }) * page_size;
-            Some(guard)
-        } else if cfg!(any(target_os = "openbsd", target_os = "netbsd")) {
-            // OpenBSD stack already includes a guard page, and stack is
-            // immutable.
-            // NetBSD stack includes the guard page.
-            //
-            // We'll just note where we expect rlimit to start
-            // faulting, so our handler can report "stack overflow", and
-            // trust that the kernel's own stack guard will work.
-            let stackptr = get_stack_start_aligned()?;
-            let stackaddr = stackptr.addr();
-            Some(stackaddr - page_size..stackaddr)
-        } else {
-            // Reallocate the last page of the stack.
-            // This ensures SIGBUS will be raised on
-            // stack overflow.
-            // Systems which enforce strict PAX MPROTECT do not allow
-            // to mprotect() a mapping with less restrictive permissions
-            // than the initial mmap() used, so we mmap() here with
-            // read/write permissions and only then mprotect() it to
-            // no permissions at all. See issue #50313.
-            let stackptr = get_stack_start_aligned()?;
-            let result = mmap64(
-                stackptr,
-                page_size,
-                PROT_READ | PROT_WRITE,
-                MAP_PRIVATE | MAP_ANON | MAP_FIXED,
-                -1,
-                0,
-            );
-            if result != stackptr || result == MAP_FAILED {
-                panic!("failed to allocate a guard page: {}", io::Error::last_os_error());
-            }
-
-            let result = mprotect(stackptr, page_size, PROT_NONE);
-            if result != 0 {
-                panic!("failed to protect the guard page: {}", io::Error::last_os_error());
-            }
-
-            let guardaddr = stackptr.addr();
-
-            Some(guardaddr..guardaddr + page_size)
-        }
-    }
-
-    #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]
-    pub unsafe fn current() -> Option<Guard> {
-        let stackptr = get_stack_start()?;
-        let stackaddr = stackptr.addr();
-        Some(stackaddr - PAGE_SIZE.load(Ordering::Relaxed)..stackaddr)
-    }
-
-    #[cfg(any(
-        target_os = "android",
-        target_os = "freebsd",
-        target_os = "hurd",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "l4re"
-    ))]
-    pub unsafe fn current() -> Option<Guard> {
-        let mut ret = None;
-        let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
-        #[cfg(target_os = "freebsd")]
-        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
-        #[cfg(target_os = "freebsd")]
-        let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
-        #[cfg(not(target_os = "freebsd"))]
-        let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
-        if e == 0 {
-            let mut guardsize = 0;
-            assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0);
-            if guardsize == 0 {
-                if cfg!(all(target_os = "linux", target_env = "musl")) {
-                    // musl versions before 1.1.19 always reported guard
-                    // size obtained from pthread_attr_get_np as zero.
-                    // Use page size as a fallback.
-                    guardsize = PAGE_SIZE.load(Ordering::Relaxed);
-                } else {
-                    panic!("there is no guard page");
-                }
-            }
-            let mut stackptr = crate::ptr::null_mut::<libc::c_void>();
-            let mut size = 0;
-            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackptr, &mut size), 0);
-
-            let stackaddr = stackptr.addr();
-            ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "hurd")) {
-                Some(stackaddr - guardsize..stackaddr)
-            } else if cfg!(all(target_os = "linux", target_env = "musl")) {
-                Some(stackaddr - guardsize..stackaddr)
-            } else if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))
-            {
-                // glibc used to include the guard area within the stack, as noted in the BUGS
-                // section of `man pthread_attr_getguardsize`. This has been corrected starting
-                // with glibc 2.27, and in some distro backports, so the guard is now placed at the
-                // end (below) the stack. There's no easy way for us to know which we have at
-                // runtime, so we'll just match any fault in the range right above or below the
-                // stack base to call that fault a stack overflow.
-                Some(stackaddr - guardsize..stackaddr + guardsize)
-            } else {
-                Some(stackaddr..stackaddr + guardsize)
-            };
-        }
-        if e == 0 || cfg!(target_os = "freebsd") {
-            assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
-        }
-        ret
-    }
-}
-
 // glibc >= 2.15 has a __pthread_get_minstack() function that returns
 // PTHREAD_STACK_MIN plus bytes needed for thread-local storage.
 // We need that information to avoid blowing up when a small stack
diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs
index b3a91ee1d4c..d3f2fa35b92 100644
--- a/library/std/src/sys/pal/unsupported/thread.rs
+++ b/library/std/src/sys/pal/unsupported/thread.rs
@@ -38,13 +38,3 @@ impl Thread {
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index 4b116052f8f..940f0c8423a 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -193,13 +193,3 @@ impl Thread {
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/wasip2/cabi_realloc.rs b/library/std/src/sys/pal/wasip2/cabi_realloc.rs
new file mode 100644
index 00000000000..820063173d6
--- /dev/null
+++ b/library/std/src/sys/pal/wasip2/cabi_realloc.rs
@@ -0,0 +1,65 @@
+//! This module contains a canonical definition of the `cabi_realloc` function
+//! for the component model.
+//!
+//! The component model's canonical ABI for representing datatypes in memory
+//! makes use of this function when transferring lists and strings, for example.
+//! This function behaves like C's `realloc` but also takes alignment into
+//! account.
+//!
+//! Components are notably not required to export this function, but nearly
+//! all components end up doing so currently. This definition in the standard
+//! library removes the need for all compilations to define this themselves.
+//!
+//! More information about the canonical ABI can be found at
+//! <https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md>
+//!
+//! Note that the name of this function is not standardized in the canonical ABI
+//! at this time. Instead it's a convention of the "componentization process"
+//! where a core wasm module is converted to a component to use this name.
+//! Additionally this is not the only possible definition of this function, so
+//! this is defined as a "weak" symbol. This means that other definitions are
+//! allowed to overwrite it if they are present in a compilation.
+
+use crate::alloc::{self, Layout};
+use crate::ptr;
+
+#[used]
+static FORCE_CODEGEN_OF_CABI_REALLOC: unsafe extern "C" fn(
+    *mut u8,
+    usize,
+    usize,
+    usize,
+) -> *mut u8 = cabi_realloc;
+
+#[linkage = "weak"]
+#[no_mangle]
+pub unsafe extern "C" fn cabi_realloc(
+    old_ptr: *mut u8,
+    old_len: usize,
+    align: usize,
+    new_len: usize,
+) -> *mut u8 {
+    let layout;
+    let ptr = if old_len == 0 {
+        if new_len == 0 {
+            return ptr::without_provenance_mut(align);
+        }
+        layout = Layout::from_size_align_unchecked(new_len, align);
+        alloc::alloc(layout)
+    } else {
+        debug_assert_ne!(new_len, 0, "non-zero old_len requires non-zero new_len!");
+        layout = Layout::from_size_align_unchecked(old_len, align);
+        alloc::realloc(old_ptr, layout, new_len)
+    };
+    if ptr.is_null() {
+        // Print a nice message in debug mode, but in release mode don't
+        // pull in so many dependencies related to printing so just emit an
+        // `unreachable` instruction.
+        if cfg!(debug_assertions) {
+            alloc::handle_alloc_error(layout);
+        } else {
+            super::abort_internal();
+        }
+    }
+    return ptr;
+}
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index d1d444d7b79..94aa458d2f9 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -10,8 +10,6 @@
 pub mod alloc;
 #[path = "../wasi/args.rs"]
 pub mod args;
-#[path = "../unix/cmath.rs"]
-pub mod cmath;
 #[path = "../wasi/env.rs"]
 pub mod env;
 #[path = "../wasi/fd.rs"]
@@ -28,10 +26,6 @@ pub mod io;
 pub mod net;
 #[path = "../wasi/os.rs"]
 pub mod os;
-#[path = "../unix/os_str.rs"]
-pub mod os_str;
-#[path = "../unix/path.rs"]
-pub mod path;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
@@ -72,3 +66,5 @@ pub use helpers::decode_error_kind;
 use helpers::err2io;
 pub use helpers::hashmap_random_keys;
 pub use helpers::is_interrupted;
+
+mod cabi_realloc;
diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs
index 627763da856..f93f31026f8 100644
--- a/library/std/src/sys/pal/windows/stack_overflow.rs
+++ b/library/std/src/sys/pal/windows/stack_overflow.rs
@@ -3,21 +3,12 @@
 use crate::sys::c;
 use crate::thread;
 
-use super::api;
-
-pub struct Handler;
-
-impl Handler {
-    pub unsafe fn new() -> Handler {
-        // This API isn't available on XP, so don't panic in that case and just
-        // pray it works out ok.
-        if c::SetThreadStackGuarantee(&mut 0x5000) == 0
-            && api::get_last_error().code != c::ERROR_CALL_NOT_IMPLEMENTED
-        {
-            panic!("failed to reserve stack space for exception handling");
-        }
-        Handler
-    }
+/// Reserve stack space for use in stack overflow exceptions.
+pub unsafe fn reserve_stack() {
+    let result = c::SetThreadStackGuarantee(&mut 0x5000);
+    // Reserving stack space is not critical so we allow it to fail in the released build of libstd.
+    // We still use debug assert here so that CI will test that we haven't made a mistake calling the function.
+    debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling");
 }
 
 unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> c::LONG {
@@ -36,9 +27,10 @@ unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POIN
 }
 
 pub unsafe fn init() {
-    if c::AddVectoredExceptionHandler(0, Some(vectored_handler)).is_null() {
-        panic!("failed to install exception handler");
-    }
+    let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler));
+    // Similar to the above, adding the stack overflow handler is allowed to fail
+    // but a debug assert is used so CI will still test that it normally works.
+    debug_assert!(!result.is_null(), "failed to install exception handler");
     // Set the thread stack guarantee for the main thread.
-    let _h = Handler::new();
+    reserve_stack();
 }
diff --git a/library/std/src/sys/pal/windows/stack_overflow_uwp.rs b/library/std/src/sys/pal/windows/stack_overflow_uwp.rs
index afdf7f566ae..9e9b3efaf1b 100644
--- a/library/std/src/sys/pal/windows/stack_overflow_uwp.rs
+++ b/library/std/src/sys/pal/windows/stack_overflow_uwp.rs
@@ -1,11 +1,4 @@
 #![cfg_attr(test, allow(dead_code))]
 
-pub struct Handler;
-
-impl Handler {
-    pub fn new() -> Handler {
-        Handler
-    }
-}
-
+pub unsafe fn reserve_stack() {}
 pub unsafe fn init() {}
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 970bd9c6ce7..fe174e1e340 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -48,9 +48,8 @@ impl Thread {
 
         extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
             unsafe {
-                // Next, set up our stack overflow handler which may get triggered if we run
-                // out of stack.
-                let _handler = stack_overflow::Handler::new();
+                // Next, reserve some stack space for if we otherwise run out of stack.
+                stack_overflow::reserve_stack();
                 // Finally, let's run some code.
                 Box::from_raw(main as *mut Box<dyn FnOnce()>)();
             }
@@ -144,14 +143,3 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
         cpus => Ok(unsafe { NonZero::new_unchecked(cpus) }),
     }
 }
-
-#[cfg_attr(test, allow(dead_code))]
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs
index f95ceb7343b..c1fd1c0d653 100644
--- a/library/std/src/sys/pal/xous/thread.rs
+++ b/library/std/src/sys/pal/xous/thread.rs
@@ -140,13 +140,3 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // We're unicore right now.
     Ok(unsafe { NonZero::new_unchecked(1) })
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/xous/thread_local_key.rs b/library/std/src/sys/pal/xous/thread_local_key.rs
index 2aaf46d0244..6c29813c79d 100644
--- a/library/std/src/sys/pal/xous/thread_local_key.rs
+++ b/library/std/src/sys/pal/xous/thread_local_key.rs
@@ -49,7 +49,7 @@ fn tls_ptr_addr() -> *mut *mut u8 {
             out(reg) tp,
         );
     }
-    core::ptr::from_exposed_addr_mut::<*mut u8>(tp)
+    core::ptr::with_exposed_provenance_mut::<*mut u8>(tp)
 }
 
 /// Create an area of memory that's unique per thread. This area will
diff --git a/library/std/src/sys/pal/zkvm/thread_local_key.rs b/library/std/src/sys/pal/zkvm/thread_local_key.rs
index 3ffe6247344..2f67924c618 100644
--- a/library/std/src/sys/pal/zkvm/thread_local_key.rs
+++ b/library/std/src/sys/pal/zkvm/thread_local_key.rs
@@ -9,13 +9,13 @@ pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
 
 #[inline]
 pub unsafe fn set(key: Key, value: *mut u8) {
-    let key: *mut *mut u8 = core::ptr::from_exposed_addr_mut(key);
+    let key: *mut *mut u8 = core::ptr::with_exposed_provenance_mut(key);
     *key = value;
 }
 
 #[inline]
 pub unsafe fn get(key: Key) -> *mut u8 {
-    let key: *mut *mut u8 = core::ptr::from_exposed_addr_mut(key);
+    let key: *mut *mut u8 = core::ptr::with_exposed_provenance_mut(key);
     *key
 }
 
diff --git a/library/std/src/sys/personality/dwarf/eh.rs b/library/std/src/sys/personality/dwarf/eh.rs
index a78084de0fa..3f3615ea3e0 100644
--- a/library/std/src/sys/personality/dwarf/eh.rs
+++ b/library/std/src/sys/personality/dwarf/eh.rs
@@ -125,7 +125,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
                 // Can never have null landing pad for sjlj -- that would have
                 // been indicated by a -1 call site index.
                 // FIXME(strict provenance)
-                let lpad = ptr::from_exposed_addr((cs_lpad + 1) as usize);
+                let lpad = ptr::with_exposed_provenance((cs_lpad + 1) as usize);
                 return Ok(interpret_cs_action(action_table, cs_action_entry, lpad));
             }
         }
diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs
index dce966086b8..d1918855797 100644
--- a/library/std/src/sys/sync/rwlock/queue.rs
+++ b/library/std/src/sys/sync/rwlock/queue.rs
@@ -115,8 +115,7 @@ use crate::sync::atomic::{
     AtomicBool, AtomicPtr,
     Ordering::{AcqRel, Acquire, Relaxed, Release},
 };
-use crate::sys_common::thread_info;
-use crate::thread::Thread;
+use crate::thread::{self, Thread};
 
 // Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the
 // locking operation will be retried.
@@ -203,8 +202,7 @@ impl Node {
     fn prepare(&mut self) {
         // Fall back to creating an unnamed `Thread` handle to allow locking in
         // TLS destructors.
-        self.thread
-            .get_or_init(|| thread_info::current_thread().unwrap_or_else(|| Thread::new(None)));
+        self.thread.get_or_init(|| thread::try_current().unwrap_or_else(|| Thread::new(None)));
         self.completed = AtomicBool::new(false);
     }
 
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 5410f135a73..5abf201aa20 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -26,7 +26,6 @@ pub mod io;
 pub mod lazy_box;
 pub mod process;
 pub mod thread;
-pub mod thread_info;
 pub mod thread_local_dtor;
 pub mod thread_parking;
 pub mod wstr;
diff --git a/library/std/src/sys_common/thread_info.rs b/library/std/src/sys_common/thread_info.rs
deleted file mode 100644
index ec1428ea40e..00000000000
--- a/library/std/src/sys_common/thread_info.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-#![allow(dead_code)] // stack_guard isn't used right now on all platforms
-
-use crate::cell::OnceCell;
-use crate::sys;
-use crate::sys::thread::guard::Guard;
-use crate::thread::Thread;
-
-struct ThreadInfo {
-    stack_guard: OnceCell<Guard>,
-    thread: OnceCell<Thread>,
-}
-
-thread_local! {
-   static THREAD_INFO: ThreadInfo = const { ThreadInfo {
-       stack_guard: OnceCell::new(),
-       thread: OnceCell::new()
-   } };
-}
-
-impl ThreadInfo {
-    fn with<R, F>(f: F) -> Option<R>
-    where
-        F: FnOnce(&Thread, &OnceCell<Guard>) -> R,
-    {
-        THREAD_INFO
-            .try_with(move |thread_info| {
-                let thread =
-                    thread_info.thread.get_or_init(|| Thread::new(sys::thread::Thread::get_name()));
-                f(thread, &thread_info.stack_guard)
-            })
-            .ok()
-    }
-}
-
-pub fn current_thread() -> Option<Thread> {
-    ThreadInfo::with(|thread, _| thread.clone())
-}
-
-pub fn stack_guard() -> Option<Guard> {
-    ThreadInfo::with(|_, guard| guard.get().cloned()).flatten()
-}
-
-/// Set new thread info, panicking if it has already been initialized
-#[allow(unreachable_code, unreachable_patterns)] // some platforms don't use stack_guard
-pub fn set(stack_guard: Option<Guard>, thread: Thread) {
-    THREAD_INFO.with(move |thread_info| {
-        rtassert!(thread_info.stack_guard.get().is_none() && thread_info.thread.get().is_none());
-        if let Some(guard) = stack_guard {
-            thread_info.stack_guard.set(guard).unwrap();
-        }
-        thread_info.thread.set(thread).unwrap();
-    });
-}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 85de2980133..f7eb92bc61e 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -159,7 +159,7 @@
 mod tests;
 
 use crate::any::Any;
-use crate::cell::UnsafeCell;
+use crate::cell::{OnceCell, UnsafeCell};
 use crate::ffi::{CStr, CString};
 use crate::fmt;
 use crate::io;
@@ -174,7 +174,6 @@ use crate::str;
 use crate::sync::Arc;
 use crate::sys::thread as imp;
 use crate::sys_common::thread;
-use crate::sys_common::thread_info;
 use crate::sys_common::thread_parking::Parker;
 use crate::sys_common::{AsInner, IntoInner};
 use crate::time::{Duration, Instant};
@@ -518,12 +517,8 @@ impl Builder {
 
             crate::io::set_output_capture(output_capture);
 
-            // SAFETY: we constructed `f` initialized.
             let f = f.into_inner();
-            // SAFETY: the stack guard passed is the one for the current thread.
-            // This means the current thread's stack and the new thread's stack
-            // are properly set and protected from each other.
-            thread_info::set(unsafe { imp::guard::current() }, their_thread);
+            set_current(their_thread);
             let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
                 crate::sys_common::backtrace::__rust_begin_short_backtrace(f)
             }));
@@ -683,6 +678,27 @@ where
     Builder::new().spawn(f).expect("failed to spawn thread")
 }
 
+thread_local! {
+    static CURRENT: OnceCell<Thread> = const { OnceCell::new() };
+}
+
+/// Sets the thread handle for the current thread.
+///
+/// Panics if the handle has been set already or when called from a TLS destructor.
+pub(crate) fn set_current(thread: Thread) {
+    CURRENT.with(|current| current.set(thread).unwrap());
+}
+
+/// Gets a handle to the thread that invokes it.
+///
+/// In contrast to the public `current` function, this will not panic if called
+/// from inside a TLS destructor.
+pub(crate) fn try_current() -> Option<Thread> {
+    CURRENT
+        .try_with(|current| current.get_or_init(|| Thread::new(imp::Thread::get_name())).clone())
+        .ok()
+}
+
 /// Gets a handle to the thread that invokes it.
 ///
 /// # Examples
@@ -705,7 +721,7 @@ where
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn current() -> Thread {
-    thread_info::current_thread().expect(
+    try_current().expect(
         "use of std::thread::current() is not possible \
          after the thread's local data has been destroyed",
     )
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 74a924d86c7..4b182a7a693 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -150,7 +150,7 @@ fn main() {
         {
             cmd.arg("-Ztls-model=initial-exec");
         }
-    } else if std::env::var("MIRI").is_err() {
+    } else {
         // Find any host flags that were passed by bootstrap.
         // The flags are stored in a RUSTC_HOST_FLAGS variable, separated by spaces.
         if let Ok(flags) = std::env::var("RUSTC_HOST_FLAGS") {
@@ -220,6 +220,12 @@ fn main() {
         }
     }
 
+    if env::var_os("RUSTC_BOLT_LINK_FLAGS").is_some() {
+        if let Some("rustc_driver") = crate_name {
+            cmd.arg("-Clink-args=-Wl,-q");
+        }
+    }
+
     let is_test = args.iter().any(|a| a == "--test");
     if verbose > 2 {
         let rust_env_vars =
@@ -244,12 +250,6 @@ fn main() {
         eprintln!("{prefix} libdir: {libdir:?}");
     }
 
-    if env::var_os("RUSTC_BOLT_LINK_FLAGS").is_some() {
-        if let Some("rustc_driver") = crate_name {
-            cmd.arg("-Clink-args=-Wl,-q");
-        }
-    }
-
     bin_helpers::maybe_dump(format!("stage{stage}-rustc"), &cmd);
 
     let start = Instant::now();
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index d40a3ea4c88..e03997181ee 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -643,13 +643,13 @@ impl Step for StdLink {
             t!(fs::create_dir_all(&sysroot_bin_dir));
             builder.cp_link_r(&stage0_bin_dir, &sysroot_bin_dir);
 
-            // Copy all *.so files from stage0/lib to stage0-sysroot/lib
+            // Copy all files from stage0/lib to stage0-sysroot/lib
             let stage0_lib_dir = builder.out.join(host).join("stage0/lib");
             if let Ok(files) = fs::read_dir(stage0_lib_dir) {
                 for file in files {
                     let file = t!(file);
                     let path = file.path();
-                    if path.is_file() && is_dylib(&file.file_name().into_string().unwrap()) {
+                    if path.is_file() {
                         builder
                             .copy_link(&path, &sysroot.join("lib").join(path.file_name().unwrap()));
                     }
@@ -825,6 +825,7 @@ fn cp_rustc_component_to_ci_sysroot(
 #[derive(Debug, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)]
 pub struct Rustc {
     pub target: TargetSelection,
+    /// The **previous** compiler used to compile this compiler.
     pub compiler: Compiler,
     /// Whether to build a subset of crates, rather than the whole compiler.
     ///
@@ -1130,12 +1131,6 @@ pub fn rustc_cargo_env(
         cargo.env("CFG_DEFAULT_LINKER", s);
     }
 
-    if builder.config.rustc_parallel {
-        // keep in sync with `bootstrap/lib.rs:Build::rustc_features`
-        // `cfg` option for rustc, `features` option for cargo, for conditional compilation
-        cargo.rustflag("--cfg=parallel_compiler");
-        cargo.rustdocflag("--cfg=parallel_compiler");
-    }
     if builder.config.rust_verify_llvm_ir {
         cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
     }
@@ -1518,12 +1513,9 @@ impl Step for Sysroot {
         run.never()
     }
 
-    /// Returns the sysroot for the `compiler` specified that *this build system
-    /// generates*.
-    ///
-    /// That is, the sysroot for the stage0 compiler is not what the compiler
-    /// thinks it is by default, but it's the same as the default for stages
-    /// 1-3.
+    /// 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.
     fn run(self, builder: &Builder<'_>) -> PathBuf {
         let compiler = self.compiler;
         let host_dir = builder.out.join(compiler.host.triple);
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index d9c7032d0db..ecea62140a2 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -995,9 +995,9 @@ impl Step for PlainSourceTarball {
         if builder.rust_info().is_managed_git_subrepository()
             || builder.rust_info().is_from_tarball()
         {
-            if builder.rust_info().is_managed_git_subrepository() {
-                // Ensure we have the submodules checked out.
-                builder.update_submodule(Path::new("src/tools/cargo"));
+            // Ensure we have all submodules from src and other directories checked out.
+            for submodule in builder.get_all_submodules() {
+                builder.update_submodule(Path::new(submodule));
             }
 
             // Vendor all Cargo dependencies
@@ -1028,6 +1028,20 @@ impl Step for PlainSourceTarball {
             builder.create(&cargo_config_dir.join("config.toml"), &config);
         }
 
+        // Delete extraneous directories
+        // FIXME: if we're managed by git, we should probably instead ask git if the given path
+        // is managed by it?
+        for entry in walkdir::WalkDir::new(tarball.image_dir())
+            .follow_links(true)
+            .into_iter()
+            .filter_map(|e| e.ok())
+        {
+            if entry.path().is_dir() && entry.path().file_name() == Some(OsStr::new("__pycache__"))
+            {
+                t!(fs::remove_dir_all(entry.path()));
+            }
+        }
+
         tarball.bare()
     }
 }
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 3da927b5fa0..e461e11677f 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -274,6 +274,7 @@ impl Step for Llvm {
             target.to_string()
         };
 
+        // If LLVM has already been built or been downloaded through download-ci-llvm, we avoid building it again.
         let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target) {
             Ok(p) => return p,
             Err(m) => m,
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index 61ee2fc1f6f..7028bffea54 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -121,8 +121,6 @@ impl Step for ReplaceVersionPlaceholder {
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Miri {
-    stage: u32,
-    host: TargetSelection,
     target: TargetSelection,
 }
 
@@ -135,29 +133,35 @@ impl Step for Miri {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(Miri {
-            stage: run.builder.top_stage,
-            host: run.build_triple(),
-            target: run.target,
-        });
+        run.builder.ensure(Miri { target: run.target });
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let stage = self.stage;
-        let host = self.host;
+        let host = builder.build.build;
         let target = self.target;
-        let compiler = builder.compiler(stage, host);
-
-        let miri =
-            builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() });
-        let miri_sysroot = test::Miri::build_miri_sysroot(builder, compiler, &miri, target);
+        let stage = builder.top_stage;
+        if stage == 0 {
+            eprintln!("miri cannot be run at stage 0");
+            std::process::exit(1);
+        }
+
+        // This compiler runs on the host, we'll just use it for the target.
+        let target_compiler = builder.compiler(stage, host);
+        // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
+        // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
+        // compilers, which isn't what we want. Rustdoc should be linked in the same way as the
+        // rustc compiler it's paired with, so it must be built with the previous stage compiler.
+        let host_compiler = builder.compiler(stage - 1, host);
+
+        // Get a target sysroot for Miri.
+        let miri_sysroot = test::Miri::build_miri_sysroot(builder, target_compiler, target);
 
         // # Run miri.
         // Running it via `cargo run` as that figures out the right dylib path.
         // add_rustc_lib_path does not add the path that contains librustc_driver-<...>.so.
         let mut miri = tool::prepare_tool_cargo(
             builder,
-            compiler,
+            host_compiler,
             Mode::ToolRustc,
             host,
             "run",
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 48596af7ca0..8a79c28fc6c 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -493,8 +493,6 @@ impl Step for RustDemangler {
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Miri {
-    stage: u32,
-    host: TargetSelection,
     target: TargetSelection,
 }
 
@@ -503,41 +501,26 @@ impl Miri {
     pub fn build_miri_sysroot(
         builder: &Builder<'_>,
         compiler: Compiler,
-        miri: &Path,
         target: TargetSelection,
     ) -> String {
         let miri_sysroot = builder.out.join(compiler.host.triple).join("miri-sysroot");
-        let mut cargo = tool::prepare_tool_cargo(
+        let mut cargo = builder::Cargo::new(
             builder,
             compiler,
-            Mode::ToolRustc,
-            compiler.host,
-            "run",
-            "src/tools/miri/cargo-miri",
-            SourceType::InTree,
-            &[],
+            Mode::Std,
+            SourceType::Submodule,
+            target,
+            "miri-setup",
         );
-        cargo.add_rustc_lib_path(builder);
-        cargo.arg("--").arg("miri").arg("setup");
-        cargo.arg("--target").arg(target.rustc_target_arg());
 
         // Tell `cargo miri setup` where to find the sources.
         cargo.env("MIRI_LIB_SRC", builder.src.join("library"));
-        // Tell it where to find Miri.
-        cargo.env("MIRI", miri);
         // Tell it where to put the sysroot.
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
-        // Debug things.
-        cargo.env("RUST_BACKTRACE", "1");
 
         let mut cargo = Command::from(cargo);
-        let _guard = builder.msg(
-            Kind::Build,
-            compiler.stage + 1,
-            "miri sysroot",
-            compiler.host,
-            compiler.host,
-        );
+        let _guard =
+            builder.msg(Kind::Build, compiler.stage, "miri sysroot", compiler.host, target);
         builder.run(&mut cargo);
 
         // # Determine where Miri put its sysroot.
@@ -574,41 +557,51 @@ impl Step for Miri {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(Miri {
-            stage: run.builder.top_stage,
-            host: run.build_triple(),
-            target: run.target,
-        });
+        run.builder.ensure(Miri { target: run.target });
     }
 
     /// Runs `cargo test` for miri.
     fn run(self, builder: &Builder<'_>) {
-        let stage = self.stage;
-        let host = self.host;
+        let host = builder.build.build;
         let target = self.target;
-        let compiler = builder.compiler(stage, host);
-        // We need the stdlib for the *next* stage, as it was built with this compiler that also built Miri.
-        // Except if we are at stage 2, the bootstrap loop is complete and we can stick with our current stage.
-        let compiler_std = builder.compiler(if stage < 2 { stage + 1 } else { stage }, host);
-
-        let miri =
-            builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() });
-        let _cargo_miri = builder.ensure(tool::CargoMiri {
-            compiler,
-            target: self.host,
+        let stage = builder.top_stage;
+        if stage == 0 {
+            eprintln!("miri cannot be tested at stage 0");
+            std::process::exit(1);
+        }
+
+        // This compiler runs on the host, we'll just use it for the target.
+        let target_compiler = builder.compiler(stage, host);
+        // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
+        // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
+        // compilers, which isn't what we want. Rustdoc should be linked in the same way as the
+        // rustc compiler it's paired with, so it must be built with the previous stage compiler.
+        let host_compiler = builder.compiler(stage - 1, host);
+
+        // Build our tools.
+        let miri = builder.ensure(tool::Miri {
+            compiler: host_compiler,
+            target: host,
+            extra_features: Vec::new(),
+        });
+        // the ui tests also assume cargo-miri has been built
+        builder.ensure(tool::CargoMiri {
+            compiler: host_compiler,
+            target: host,
             extra_features: Vec::new(),
         });
-        // The stdlib we need might be at a different stage. And just asking for the
-        // sysroot does not seem to populate it, so we do that first.
-        builder.ensure(compile::Std::new(compiler_std, host));
-        let sysroot = builder.sysroot(compiler_std);
-        // We also need a Miri sysroot.
-        let miri_sysroot = Miri::build_miri_sysroot(builder, compiler, &miri, target);
+
+        // We also need sysroots, for Miri and for the host (the latter for build scripts).
+        // This is for the tests so everything is done with the target compiler.
+        let miri_sysroot = Miri::build_miri_sysroot(builder, target_compiler, target);
+        builder.ensure(compile::Std::new(target_compiler, host));
+        let sysroot = builder.sysroot(target_compiler);
 
         // # Run `cargo test`.
+        // This is with the Miri crate, so it uses the host compiler.
         let mut cargo = tool::prepare_tool_cargo(
             builder,
-            compiler,
+            host_compiler,
             Mode::ToolRustc,
             host,
             "test",
@@ -616,26 +609,23 @@ impl Step for Miri {
             SourceType::InTree,
             &[],
         );
-        let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "miri", host, target);
 
         cargo.add_rustc_lib_path(builder);
 
+        // We can NOT use `run_cargo_test` since Miri's integration tests do not use the usual test
+        // harness and therefore do not understand the flags added by `add_flags_and_try_run_test`.
+        let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", host_compiler, host, builder);
+
         // miri tests need to know about the stage sysroot
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
         cargo.env("MIRI_HOST_SYSROOT", &sysroot);
         cargo.env("MIRI", &miri);
-        if builder.config.locked_deps {
-            // enforce lockfiles
-            cargo.env("CARGO_EXTRA_FLAGS", "--locked");
-        }
 
         // Set the target.
         cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
 
-        // This can NOT be `run_cargo_test` since the Miri test runner
-        // does not understand the flags added by `add_flags_and_try_run_test`.
-        let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder);
         {
+            let _guard = builder.msg_sysroot_tool(Kind::Test, stage, "miri", host, target);
             let _time = helpers::timeit(builder);
             builder.run(&mut cargo);
         }
@@ -650,8 +640,14 @@ impl Step for Miri {
             // Optimizations can change error locations and remove UB so don't run `fail` tests.
             cargo.args(["tests/pass", "tests/panic"]);
 
-            let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder);
             {
+                let _guard = builder.msg_sysroot_tool(
+                    Kind::Test,
+                    stage,
+                    "miri (mir-opt-level 4)",
+                    host,
+                    target,
+                );
                 let _time = helpers::timeit(builder);
                 builder.run(&mut cargo);
             }
@@ -660,42 +656,40 @@ impl Step for Miri {
         // # Run `cargo miri test`.
         // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures
         // that we get the desired output), but that is sufficient to make sure that the libtest harness
-        // itself executes properly under Miri.
+        // itself executes properly under Miri, and that all the logic in `cargo-miri` does not explode.
+        // This is running the build `cargo-miri` for the given target, so we need the target compiler.
         let mut cargo = tool::prepare_tool_cargo(
             builder,
-            compiler,
-            Mode::ToolRustc,
-            host,
-            "run",
-            "src/tools/miri/cargo-miri",
+            target_compiler,
+            Mode::ToolStd, // it's unclear what to use here, we're not building anything just doing a smoke test!
+            target,
+            "miri-test",
+            "src/tools/miri/test-cargo-miri",
             SourceType::Submodule,
             &[],
         );
-        cargo.add_rustc_lib_path(builder);
-        cargo.arg("--").arg("miri").arg("test");
-        if builder.config.locked_deps {
-            cargo.arg("--locked");
-        }
-        cargo
-            .arg("--manifest-path")
-            .arg(builder.src.join("src/tools/miri/test-cargo-miri/Cargo.toml"));
-        cargo.arg("--target").arg(target.rustc_target_arg());
-        cargo.arg("--").args(builder.config.test_args());
 
-        // `prepare_tool_cargo` sets RUSTDOC to the bootstrap wrapper and RUSTDOC_REAL to a dummy path as this is a "run", not a "test".
-        // Also, we want the rustdoc from the "next" stage for the same reason that we build a std from the next stage.
-        // So let's just set that here, and bypass bootstrap's RUSTDOC (just like cargo-miri already ignores bootstrap's RUSTC_WRAPPER).
-        cargo.env("RUSTDOC", builder.rustdoc(compiler_std));
+        // We're not using `prepare_cargo_test` so we have to do this ourselves.
+        // (We're not using that as the test-cargo-miri crate is not known to bootstrap.)
+        match builder.doc_tests {
+            DocTests::Yes => {}
+            DocTests::No => {
+                cargo.args(["--lib", "--bins", "--examples", "--tests", "--benches"]);
+            }
+            DocTests::Only => {
+                cargo.arg("--doc");
+            }
+        }
 
-        // Tell `cargo miri` where to find things.
+        // Tell `cargo miri` where to find the sysroots.
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
         cargo.env("MIRI_HOST_SYSROOT", sysroot);
-        cargo.env("MIRI", &miri);
-        // Debug things.
-        cargo.env("RUST_BACKTRACE", "1");
 
+        // Finally, pass test-args and run everything.
+        cargo.arg("--").args(builder.config.test_args());
         let mut cargo = Command::from(cargo);
         {
+            let _guard = builder.msg_sysroot_tool(Kind::Test, stage, "cargo-miri", host, target);
             let _time = helpers::timeit(builder);
             builder.run(&mut cargo);
         }
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index deab3fce54c..1edf65d28b7 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -469,7 +469,7 @@ impl Step for Rustdoc {
             features.push("jemalloc".to_string());
         }
 
-        let mut cargo = prepare_tool_cargo(
+        let cargo = prepare_tool_cargo(
             builder,
             build_compiler,
             Mode::ToolRustc,
@@ -480,10 +480,6 @@ impl Step for Rustdoc {
             features.as_slice(),
         );
 
-        if builder.config.rustc_parallel {
-            cargo.rustflag("--cfg=parallel_compiler");
-        }
-
         let _guard = builder.msg_tool(
             Mode::ToolRustc,
             "rustdoc",
@@ -732,7 +728,7 @@ impl Step for LlvmBitcodeLinker {
         builder.ensure(compile::Std::new(self.compiler, self.compiler.host));
         builder.ensure(compile::Rustc::new(self.compiler, self.target));
 
-        let mut cargo = prepare_tool_cargo(
+        let cargo = prepare_tool_cargo(
             builder,
             self.compiler,
             Mode::ToolRustc,
@@ -743,10 +739,6 @@ impl Step for LlvmBitcodeLinker {
             &self.extra_features,
         );
 
-        if builder.config.rustc_parallel {
-            cargo.rustflag("--cfg=parallel_compiler");
-        }
-
         builder.run(&mut cargo.into());
 
         let tool_out = builder
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 7f93fdc72ef..0cce5130f64 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -554,29 +554,7 @@ impl<'a> ShouldRun<'a> {
     ///
     /// [`path`]: ShouldRun::path
     pub fn paths(mut self, paths: &[&str]) -> Self {
-        static SUBMODULES_PATHS: OnceLock<Vec<String>> = OnceLock::new();
-
-        let init_submodules_paths = |src: &PathBuf| {
-            let file = File::open(src.join(".gitmodules")).unwrap();
-
-            let mut submodules_paths = vec![];
-            for line in BufReader::new(file).lines() {
-                if let Ok(line) = line {
-                    let line = line.trim();
-
-                    if line.starts_with("path") {
-                        let actual_path =
-                            line.split(' ').last().expect("Couldn't get value of path");
-                        submodules_paths.push(actual_path.to_owned());
-                    }
-                }
-            }
-
-            submodules_paths
-        };
-
-        let submodules_paths =
-            SUBMODULES_PATHS.get_or_init(|| init_submodules_paths(&self.builder.src));
+        let submodules_paths = self.builder.get_all_submodules();
 
         self.paths.insert(PathSet::Set(
             paths
@@ -1031,10 +1009,10 @@ impl<'a> Builder<'a> {
         StepDescription::run(v, self, paths);
     }
 
-    /// Obtain a compiler at a given stage and for a given host. 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).
+    /// Obtain a compiler at a given stage and for a given host (i.e., this is the target that the
+    /// 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).
     pub fn compiler(&self, stage: u32, host: TargetSelection) -> Compiler {
         self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } })
     }
@@ -1216,20 +1194,11 @@ impl<'a> Builder<'a> {
     }
 
     pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> Command {
-        let initial_sysroot_bin = self.initial_rustc.parent().unwrap();
-        // Set PATH to include the sysroot bin dir so clippy can find cargo.
-        // FIXME: once rust-clippy#11944 lands on beta, set `CARGO` directly instead.
-        let path = t!(env::join_paths(
-            // The sysroot comes first in PATH to avoid using rustup's cargo.
-            std::iter::once(PathBuf::from(initial_sysroot_bin))
-                .chain(env::split_paths(&t!(env::var("PATH"))))
-        ));
-
         if run_compiler.stage == 0 {
             // `ensure(Clippy { stage: 0 })` *builds* clippy with stage0, it doesn't use the beta clippy.
             let cargo_clippy = self.build.config.download_clippy();
             let mut cmd = Command::new(cargo_clippy);
-            cmd.env("PATH", &path);
+            cmd.env("CARGO", &self.initial_cargo);
             return cmd;
         }
 
@@ -1249,7 +1218,37 @@ impl<'a> Builder<'a> {
 
         let mut cmd = Command::new(cargo_clippy);
         cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
-        cmd.env("PATH", path);
+        cmd.env("CARGO", &self.initial_cargo);
+        cmd
+    }
+
+    pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> Command {
+        assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0");
+        let build_compiler = self.compiler(run_compiler.stage - 1, self.build.build);
+
+        let miri = self.ensure(tool::Miri {
+            compiler: build_compiler,
+            target: self.build.build,
+            extra_features: Vec::new(),
+        });
+        let cargo_miri = self.ensure(tool::CargoMiri {
+            compiler: build_compiler,
+            target: self.build.build,
+            extra_features: Vec::new(),
+        });
+        // Invoke cargo-miri, make sure we can find miri and cargo.
+        let mut cmd = Command::new(cargo_miri);
+        cmd.env("MIRI", &miri);
+        cmd.env("CARGO", &self.initial_cargo);
+        // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler`,
+        // so they match the Miri we just built. However this means they are actually living one
+        // stage up, i.e. we are running `stage0-tools-bin/miri` with the libraries in `stage1/lib`.
+        // This is an unfortunate off-by-1 caused (possibly) by the fact that Miri doesn't have an
+        // "assemble" step like rustc does that would cross the stage boundary. We can't use
+        // `add_rustc_lib_path` as that's a NOP on Windows but we do need these libraries added to
+        // the PATH due to the stage mismatch.
+        // Also see https://github.com/rust-lang/rust/pull/123192#issuecomment-2028901503.
+        add_dylib_path(self.rustc_lib_paths(run_compiler), &mut cmd);
         cmd
     }
 
@@ -1294,20 +1293,26 @@ impl<'a> Builder<'a> {
         compiler: Compiler,
         mode: Mode,
         target: TargetSelection,
-        cmd: &str,
+        cmd: &str, // FIXME make this properly typed
     ) -> Command {
-        let mut cargo = if cmd == "clippy" {
-            self.cargo_clippy_cmd(compiler)
+        let mut cargo;
+        if cmd == "clippy" {
+            cargo = self.cargo_clippy_cmd(compiler);
+            cargo.arg(cmd);
+        } else if let Some(subcmd) = cmd.strip_prefix("miri-") {
+            cargo = self.cargo_miri_cmd(compiler);
+            cargo.arg("miri").arg(subcmd);
         } else {
-            Command::new(&self.initial_cargo)
-        };
+            cargo = Command::new(&self.initial_cargo);
+            cargo.arg(cmd);
+        }
 
         // Run cargo from the source root so it can find .cargo/config.
         // This matters when using vendoring and the working directory is outside the repository.
         cargo.current_dir(&self.src);
 
         let out_dir = self.stage_out(compiler, mode);
-        cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd);
+        cargo.env("CARGO_TARGET_DIR", &out_dir);
 
         // Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
         // from out of tree it shouldn't matter, since x.py is only used for
@@ -1337,7 +1342,8 @@ impl<'a> Builder<'a> {
 
         if self.config.rust_optimize.is_release() {
             // FIXME: cargo bench/install do not accept `--release`
-            if cmd != "bench" && cmd != "install" {
+            // and miri doesn't want it
+            if cmd != "bench" && cmd != "install" && !cmd.starts_with("miri-") {
                 cargo.arg("--release");
             }
         }
@@ -1353,14 +1359,15 @@ impl<'a> Builder<'a> {
     /// Cargo. This cargo will be configured to use `compiler` as the actual
     /// rustc compiler, its output will be scoped by `mode`'s output directory,
     /// it will pass the `--target` flag for the specified `target`, and will be
-    /// executing the Cargo command `cmd`.
+    /// executing the Cargo command `cmd`. `cmd` can be `miri-cmd` for commands
+    /// to be run with Miri.
     fn cargo(
         &self,
         compiler: Compiler,
         mode: Mode,
         source_type: SourceType,
         target: TargetSelection,
-        cmd: &str,
+        cmd: &str, // FIXME make this properly typed
     ) -> Cargo {
         let mut cargo = self.bare_cargo(compiler, mode, target, cmd);
         let out_dir = self.stage_out(compiler, mode);
@@ -1671,7 +1678,8 @@ impl<'a> Builder<'a> {
             .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
             .env(
                 "RUSTDOC_REAL",
-                if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) {
+                // Make sure to handle both `test` and `miri-test` commands.
+                if cmd == "doc" || cmd == "rustdoc" || (cmd.ends_with("test") && want_rustdoc) {
                     self.rustdoc(compiler)
                 } else {
                     PathBuf::from("/path/to/nowhere/rustdoc/not/required")
@@ -2067,6 +2075,15 @@ impl<'a> Builder<'a> {
             rustflags.arg("-Zinline-mir");
         }
 
+        if self.config.rustc_parallel
+            && matches!(mode, Mode::ToolRustc | Mode::Rustc | Mode::Codegen)
+        {
+            // keep in sync with `bootstrap/lib.rs:Build::rustc_features`
+            // `cfg` option for rustc, `features` option for cargo, for conditional compilation
+            rustflags.arg("--cfg=parallel_compiler");
+            rustdocflags.arg("--cfg=parallel_compiler");
+        }
+
         // set rustc args passed from command line
         let rustc_args =
             self.config.cmd.rustc_args().iter().map(|s| s.to_string()).collect::<Vec<_>>();
@@ -2151,6 +2168,37 @@ impl<'a> Builder<'a> {
         out
     }
 
+    /// Return paths of all submodules managed by git.
+    /// If the current checkout is not managed by git, returns an empty slice.
+    pub fn get_all_submodules(&self) -> &[String] {
+        if !self.rust_info().is_managed_git_subrepository() {
+            return &[];
+        }
+
+        static SUBMODULES_PATHS: OnceLock<Vec<String>> = OnceLock::new();
+
+        let init_submodules_paths = |src: &PathBuf| {
+            let file = File::open(src.join(".gitmodules")).unwrap();
+
+            let mut submodules_paths = vec![];
+            for line in BufReader::new(file).lines() {
+                if let Ok(line) = line {
+                    let line = line.trim();
+
+                    if line.starts_with("path") {
+                        let actual_path =
+                            line.split(' ').last().expect("Couldn't get value of path");
+                        submodules_paths.push(actual_path.to_owned());
+                    }
+                }
+            }
+
+            submodules_paths
+        };
+
+        &SUBMODULES_PATHS.get_or_init(|| init_submodules_paths(&self.src))
+    }
+
     /// Ensure that a given step is built *only if it's supposed to be built by default*, returning
     /// its output. This will cache the step, so it's safe (and good!) to call this as often as
     /// needed to ensure that all dependencies are build.
@@ -2300,7 +2348,7 @@ impl Cargo {
         mode: Mode,
         source_type: SourceType,
         target: TargetSelection,
-        cmd: &str,
+        cmd: &str, // FIXME make this properly typed
     ) -> Cargo {
         let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd);
         cargo.configure_linker(builder);
@@ -2314,7 +2362,7 @@ impl Cargo {
         mode: Mode,
         source_type: SourceType,
         target: TargetSelection,
-        cmd: &str,
+        cmd: &str, // FIXME make this properly typed
     ) -> Cargo {
         builder.cargo(compiler, mode, source_type, target, cmd)
     }
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 0f977640559..178df633cec 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -599,7 +599,6 @@ mod dist {
             pass: None,
             run: None,
             only_modified: false,
-            skip: vec![],
             extra_checks: None,
         };
 
@@ -664,7 +663,6 @@ mod dist {
             no_fail_fast: false,
             doc: true,
             no_doc: false,
-            skip: vec![],
             bless: false,
             force_rerun: false,
             compare_mode: None,
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 7262b785ee0..a66f743a1c5 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -339,9 +339,6 @@ pub enum Subcommand {
         #[arg(long)]
         /// run all tests regardless of failure
         no_fail_fast: bool,
-        #[arg(long, value_name = "SUBSTRING")]
-        /// skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times
-        skip: Vec<PathBuf>,
         #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
         /// extra arguments to be passed for the test tool being used
         /// (e.g. libtest, compiletest or rustdoc)
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index d8397ab51de..44452446eb8 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -250,6 +250,8 @@ pub enum Mode {
     /// directory. This is for miscellaneous sets of tools that are built
     /// using the bootstrap stage0 compiler in its entirety (target libraries
     /// and all). Typically these tools compile with stable Rust.
+    ///
+    /// Only works for stage 0.
     ToolBootstrap,
 
     /// Build a tool which uses the locally built std, placing output in the
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index e5aa81d83d5..6918574814f 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -60,7 +60,7 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
            /scripts/validate-error-codes.sh && \
            reuse --include-submodules lint && \
            # Runs checks to ensure that there are no ES5 issues in our JS code.
-           es-check es6 ../src/librustdoc/html/static/js/*.js && \
+           es-check es8 ../src/librustdoc/html/static/js/*.js && \
            eslint -c ../src/librustdoc/html/static/.eslintrc.js ../src/librustdoc/html/static/js/*.js && \
            eslint -c ../src/tools/rustdoc-js/.eslintrc.js ../src/tools/rustdoc-js/tester.js && \
            eslint -c ../src/tools/rustdoc-gui/.eslintrc.js ../src/tools/rustdoc-gui/tester.js
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index a2b63962ba1..07feb823492 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.16.11
\ No newline at end of file
+0.17.0
\ No newline at end of file
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
index f5c426a717f..10ae7f17db7 100755
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
@@ -2,6 +2,7 @@
 # ignore-tidy-linelength
 
 set -eu
+set -x # so one can see where we are in the script
 
 X_PY="$1"
 
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index 740eb7504f8..9d72fd8a55a 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -323,6 +323,7 @@ docker \
   --env GITHUB_ACTIONS \
   --env GITHUB_REF \
   --env GITHUB_STEP_SUMMARY="/checkout/obj/${SUMMARY_FILE}" \
+  --env RUST_BACKTRACE \
   --env TOOLSTATE_REPO_ACCESS_TOKEN \
   --env TOOLSTATE_REPO \
   --env TOOLSTATE_PUBLISH \
diff --git a/src/ci/scripts/upload-artifacts.sh b/src/ci/scripts/upload-artifacts.sh
index 9755edb6dce..c9c85ec20b4 100755
--- a/src/ci/scripts/upload-artifacts.sh
+++ b/src/ci/scripts/upload-artifacts.sh
@@ -45,3 +45,17 @@ deploy_url="s3://${DEPLOY_BUCKET}/${deploy_dir}/$(ciCommit)"
 
 retry aws s3 cp --storage-class INTELLIGENT_TIERING \
     --no-progress --recursive --acl public-read "${upload_dir}" "${deploy_url}"
+
+access_url="https://ci-artifacts.rust-lang.org/${deploy_dir}/$(ciCommit)"
+
+# Output URLs to the uploaded artifacts to GitHub summary (if it is available)
+# to make them easily accessible.
+if [ -n "${GITHUB_STEP_SUMMARY}" ]
+then
+  echo "# CI artifacts" >> "${GITHUB_STEP_SUMMARY}"
+
+  for filename in "${upload_dir}"/*.xz; do
+    filename=`basename "${filename}"`
+    echo "- [${filename}](${access_url}/${filename})" >> "${GITHUB_STEP_SUMMARY}"
+  done
+fi
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index 4a4f1ae98e4..c8f5d649570 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -553,9 +553,17 @@ Supported values for this option are:
   of MSVC).
 - `debuginfo` - debuginfo sections and debuginfo symbols from the symbol table
   section are stripped at link time and are not copied to the produced binary
-  or separate files.
-- `symbols` - same as `debuginfo`, but the rest of the symbol table section is
-  stripped as well if the linker supports it.
+  or separate files. This should leave backtraces mostly-intact but may make
+  using a debugger like gdb or lldb ineffectual.
+- `symbols` - same as `debuginfo`, but the rest of the symbol table section is stripped as well,
+  depending on platform support. On platforms which depend on this symbol table for backtraces,
+  profiling, and similar, this can affect them so negatively as to make the trace incomprehensible.
+  Programs which may be combined with others, such as CLI pipelines and developer tooling,
+  or even anything which wants crash-reporting, should usually avoid `-Cstrip=symbols`.
+
+Note that, at any level, removing debuginfo only necessarily impacts "friendly" introspection.
+`-Cstrip` cannot be relied on as a meaningful security or obfuscation measure, as disassemblers
+and decompilers can extract considerable information even in the absence of symbols.
 
 ## symbol-mangling-version
 
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 75d38dd20bd..aa982a44503 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -203,6 +203,7 @@ target | std | notes
 [`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 64-bit UEFI
 
 [^x86_32-floats-x87]: Floating-point support on `i586` targets is non-compliant: the `x87` registers and instructions used for these targets do not provide IEEE-754-compliant behavior, in particular when it comes to rounding and NaN payload bits. See [issue #114479][x86-32-float-issue].
+
 [wasi-rename]: https://github.com/rust-lang/compiler-team/issues/607
 
 [Fortanix ABI]: https://edp.fortanix.com/
diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md
index 3891d6d3148..ef9337befa6 100644
--- a/src/doc/rustc/src/platform-support/netbsd.md
+++ b/src/doc/rustc/src/platform-support/netbsd.md
@@ -13,7 +13,7 @@ are currently defined running NetBSD:
 
 |          Target name           | NetBSD Platform |
 |--------------------------------|-----------------|
-| `amd64-unknown-netbsd`         | [amd64 / x86_64 systems](https://wiki.netbsd.org/ports/amd64/) |
+| `x86_64-unknown-netbsd`        | [amd64 / x86_64 systems](https://wiki.netbsd.org/ports/amd64/) |
 | `armv7-unknown-netbsd-eabihf`  | [32-bit ARMv7 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) |
 | `armv6-unknown-netbsd-eabihf`  | [32-bit ARMv6 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) |
 | `aarch64-unknown-netbsd`       | [64-bit ARM systems, little-endian](https://wiki.netbsd.org/ports/evbarm/) |
@@ -22,7 +22,7 @@ are currently defined running NetBSD:
 | `i686-unknown-netbsd`          | [32-bit i386 with SSE](https://wiki.netbsd.org/ports/i386/) |
 | `mipsel-unknown-netbsd`        | [32-bit mips, requires mips32 cpu support](https://wiki.netbsd.org/ports/evbmips/) |
 | `powerpc-unknown-netbsd`       | [Various 32-bit PowerPC systems, e.g. MacPPC](https://wiki.netbsd.org/ports/macppc/) |
-| `riscv64gc-unknown-netbsd`     | [64-bit RISC-V](https://wiki.netbsd.org/ports/riscv/)
+| `riscv64gc-unknown-netbsd`     | [64-bit RISC-V](https://wiki.netbsd.org/ports/riscv/) |
 | `sparc64-unknown-netbsd`       | [Sun UltraSPARC systems](https://wiki.netbsd.org/ports/sparc64/) |
 
 All use the "native" `stdc++` library which goes along with the natively
@@ -43,7 +43,7 @@ bug reporting system.
 
 ## Requirements
 
-The `amd64-unknown-netbsd` artifacts is being distributed by the
+The `x86_64-unknown-netbsd` artifacts is being distributed by the
 rust project.
 
 The other targets are built by the designated developers (see above),
@@ -95,7 +95,7 @@ capable systems we build and test `firefox` (amd64, i386, aarch64).
 
 ## Building Rust programs
 
-Rust ships pre-compiled artifacts for the `amd64-unknown-netbsd`
+Rust ships pre-compiled artifacts for the `x86_64-unknown-netbsd`
 target.
 
 For the other systems mentioned above, using the `pkgsrc` route is
diff --git a/src/doc/unstable-book/src/compiler-flags/external-clangrt.md b/src/doc/unstable-book/src/compiler-flags/external-clangrt.md
new file mode 100644
index 00000000000..76b78d733e5
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/external-clangrt.md
@@ -0,0 +1,6 @@
+# `external-clangrt`
+
+This option controls whether the compiler links in its own runtime library for
+[sanitizers](./sanitizer.md). Passing this flag makes the compiler *not* link
+its own library. For more information, see the section in the sanitizers doc on
+[working with other languages.](./sanitizer.md#working-with-other-languages)
diff --git a/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md b/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md
index 424f1128e3b..65219dc68e9 100644
--- a/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md
+++ b/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md
@@ -10,11 +10,9 @@ This flag accepts a comma-separated list of values and may be specified multiple
 
 - `macro` - apply remappings to the expansion of `std::file!()` macro. This is where paths in embedded panic messages come from
 - `diagnostics` - apply remappings to printed compiler diagnostics
-- `unsplit-debuginfo` - apply remappings to debug information only when they are written to compiled executables or libraries, but not when they are in split debuginfo files
-- `split-debuginfo` - apply remappings to debug information only when they are written to split debug information files, but not in compiled executables or libraries
-- `split-debuginfo-path` - apply remappings to the paths pointing to split debug information files. Does nothing when these files are not generated.
-- `object` - an alias for `macro,unsplit-debuginfo,split-debuginfo-path`. This ensures all paths in compiled executables or libraries are remapped, but not elsewhere.
-- `all` and `true` - an alias for all of the above, also equivalent to supplying only `--remap-path-prefix` without `--remap-path-scope`.
+- `debuginfo` - apply remappings to debug informations
+- `object` - apply remappings to all paths in compiled executables or libraries, but not elsewhere. Currently an alias for `macro,debuginfo`.
+- `all` - an alias for all of the above, also equivalent to supplying only `--remap-path-prefix` without `--remap-path-scope`.
 
 ## Example
 ```sh
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index c8fd154a00e..72b44e002b4 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -45,6 +45,9 @@ To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=cfi`,
 `-Zsanitizer=dataflow`,`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`,
 `-Zsanitizer=memory`, `-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or
 `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags.
+If you're working with other languages that are also instrumented with sanitizers,
+you might need the `external-clangrt` flag. See the section on
+[working with other languages](#working-with-other-languages).
 
 Example:
 ```shell
@@ -853,6 +856,18 @@ functionality][build-std].
 
 [build-std]: ../../cargo/reference/unstable.html#build-std
 
+# Working with other languages
+
+Sanitizers rely on compiler runtime libraries to function properly. Rust links
+in its own compiler runtime which might conflict with runtimes required by
+languages such as C++. Since Rust's runtime doesn't always contain the symbols
+required by C++ instrumented code, you might need to skip linking it so another
+runtime can be linked instead.
+
+A separate unstable option `-Zexternal-clangrt` can be used to make rustc skip
+linking the compiler runtime for the sanitizer. This will require you to link
+in an external runtime, such as from clang instead.
+
 # Build scripts and procedural macros
 
 Use of sanitizers together with build scripts and procedural macros is
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 9fc95fd09ba..c95516494ae 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -261,7 +261,6 @@ complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-profile-generate -
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l enable-bolt-settings -d 'Enable BOLT link flags'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -s h -l help -d 'Print help (see more with \'--help\')'
-complete -c x.py -n "__fish_seen_subcommand_from test" -l skip -d 'skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l rustc-args -d 'extra options to pass the compiler when running tests' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)' -r
@@ -274,6 +273,7 @@ complete -c x.py -n "__fish_seen_subcommand_from test" -l build -d 'build target
 complete -c x.py -n "__fish_seen_subcommand_from test" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from test" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from test" -l exclude -d 'build paths to exclude' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from test" -l skip -d 'build paths to skip' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from test" -l rustc-error-format -r -f
 complete -c x.py -n "__fish_seen_subcommand_from test" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)"
 complete -c x.py -n "__fish_seen_subcommand_from test" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index 6359b7ff086..8e505afaf75 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -333,7 +333,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             break
         }
         'x.py;test' {
-            [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times')
             [CompletionResult]::new('--test-args', 'test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)')
             [CompletionResult]::new('--rustc-args', 'rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running tests')
             [CompletionResult]::new('--extra-checks', 'extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)')
@@ -346,6 +345,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
+            [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'build paths to skip')
             [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format')
             [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure')
             [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)')
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index e1436dcde67..742f61f1622 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -1625,16 +1625,12 @@ _x.py() {
             return 0
             ;;
         x.py__test)
-            opts="-v -i -j -h --no-fail-fast --skip --test-args --rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
             fi
             case "${prev}" in
-                --skip)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
                 --test-args)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
@@ -1683,6 +1679,10 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
+                --skip)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
                 --rustc-error-format)
                     COMPREPLY=("${cur}")
                     return 0
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index ea7e4ba6758..eec610629a1 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -335,7 +335,6 @@ _arguments "${_arguments_options[@]}" \
 ;;
 (test)
 _arguments "${_arguments_options[@]}" \
-'*--skip=[skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times]:SUBSTRING:_files' \
 '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS: ' \
 '*--rustc-args=[extra options to pass the compiler when running tests]:ARGS: ' \
 '--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell)]:EXTRA_CHECKS: ' \
@@ -348,6 +347,7 @@ _arguments "${_arguments_options[@]}" \
 '--host=[host targets to build]:HOST:( )' \
 '--target=[target targets to build]:TARGET:( )' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
+'*--skip=[build paths to skip]:PATH:_files' \
 '--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \
 '--on-fail=[command to run on failure]:CMD:_cmdstring' \
 '--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \
diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands
index 615d13ccd0f..4be2dba34f6 100644
--- a/src/etc/lldb_commands
+++ b/src/etc/lldb_commands
@@ -16,4 +16,7 @@ type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)R
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::([a-z_]+::)+)PathBuf$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
 type category enable Rust
diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py
index 36c7d82b34a..a93b42e1cc4 100644
--- a/src/etc/lldb_lookup.py
+++ b/src/etc/lldb_lookup.py
@@ -58,6 +58,11 @@ def summary_lookup(valobj, dict):
     if rust_type == RustType.STD_NONZERO_NUMBER:
         return StdNonZeroNumberSummaryProvider(valobj, dict)
 
+    if rust_type == RustType.STD_PATHBUF:
+        return StdPathBufSummaryProvider(valobj, dict)
+    if rust_type == RustType.STD_PATH:
+        return StdPathSummaryProvider(valobj, dict)
+
     return ""
 
 
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index 5d2b6fd525c..1c43977a501 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -173,6 +173,35 @@ def StdStrSummaryProvider(valobj, dict):
     return '"%s"' % data
 
 
+def StdPathBufSummaryProvider(valobj, dict):
+    # type: (SBValue, dict) -> str
+    # logger = Logger.Logger()
+    # logger >> "[StdPathBufSummaryProvider] for " + str(valobj.GetName())
+    return StdOsStringSummaryProvider(valobj.GetChildMemberWithName("inner"), dict)
+
+
+def StdPathSummaryProvider(valobj, dict):
+    # type: (SBValue, dict) -> str
+    # logger = Logger.Logger()
+    # logger >> "[StdPathSummaryProvider] for " + str(valobj.GetName())
+    length = valobj.GetChildMemberWithName("length").GetValueAsUnsigned()
+    if length == 0:
+        return '""'
+
+    data_ptr = valobj.GetChildMemberWithName("data_ptr")
+
+    start = data_ptr.GetValueAsUnsigned()
+    error = SBError()
+    process = data_ptr.GetProcess()
+    data = process.ReadMemory(start, length, error)
+    if PY3:
+        try:
+            data = data.decode(encoding='UTF-8')
+        except UnicodeDecodeError:
+            return '%r' % data
+    return '"%s"' % data
+
+
 class StructSyntheticProvider:
     """Pretty-printer for structs and struct enum variants"""
 
diff --git a/src/etc/rust_types.py b/src/etc/rust_types.py
index 2b06683ef93..c0415a3cdcf 100644
--- a/src/etc/rust_types.py
+++ b/src/etc/rust_types.py
@@ -32,6 +32,8 @@ class RustType(object):
     STD_REF_MUT = "StdRefMut"
     STD_REF_CELL = "StdRefCell"
     STD_NONZERO_NUMBER = "StdNonZeroNumber"
+    STD_PATH = "StdPath"
+    STD_PATHBUF = "StdPathBuf"
 
 
 STD_STRING_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)String$")
@@ -51,6 +53,8 @@ STD_REF_REGEX = re.compile(r"^(core::([a-z_]+::)+)Ref<.+>$")
 STD_REF_MUT_REGEX = re.compile(r"^(core::([a-z_]+::)+)RefMut<.+>$")
 STD_REF_CELL_REGEX = re.compile(r"^(core::([a-z_]+::)+)RefCell<.+>$")
 STD_NONZERO_NUMBER_REGEX = re.compile(r"^(core::([a-z_]+::)+)NonZero<.+>$")
+STD_PATHBUF_REGEX = re.compile(r"^(std::([a-z_]+::)+)PathBuf$")
+STD_PATH_REGEX =  re.compile(r"^&(mut )?(std::([a-z_]+::)+)Path$")
 
 TUPLE_ITEM_REGEX = re.compile(r"__\d+$")
 
@@ -75,6 +79,8 @@ STD_TYPE_TO_REGEX = {
     RustType.STD_REF_CELL: STD_REF_CELL_REGEX,
     RustType.STD_CELL: STD_CELL_REGEX,
     RustType.STD_NONZERO_NUMBER: STD_NONZERO_NUMBER_REGEX,
+    RustType.STD_PATHBUF: STD_PATHBUF_REGEX,
+    RustType.STD_PATH: STD_PATH_REGEX,
 }
 
 def is_tuple_fields(fields):
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index bd0fbef998b..9a23811ed3f 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -9,6 +9,8 @@ path = "lib.rs"
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 askama = { version = "0.12", default-features = false, features = ["config"] }
+base64 = "0.21.7"
+byteorder = "1.5"
 itertools = "0.12"
 indexmap = "2"
 minifier = "0.3.0"
@@ -20,7 +22,7 @@ serde = { version = "1.0", features = ["derive"] }
 smallvec = "1.8.1"
 tempfile = "3"
 tracing = "0.1"
-tracing-tree = "0.2.0"
+tracing-tree = "0.3.0"
 threadpool = "1.8.1"
 
 [dependencies.tracing-subscriber]
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index fbc2c3c5af4..217f6bb550b 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -1,747 +1,367 @@
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_hir as hir;
-use rustc_hir::lang_items::LangItem;
-use rustc_middle::ty::{Region, RegionVid, TypeFoldable};
-use rustc_trait_selection::traits::auto_trait::{self, AutoTraitResult};
-
-use std::fmt::Debug;
-
-use super::*;
-
-#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
-enum RegionTarget<'tcx> {
-    Region(Region<'tcx>),
-    RegionVid(RegionVid),
-}
-
-#[derive(Default, Debug, Clone)]
-struct RegionDeps<'tcx> {
-    larger: FxHashSet<RegionTarget<'tcx>>,
-    smaller: FxHashSet<RegionTarget<'tcx>>,
-}
-
-pub(crate) struct AutoTraitFinder<'a, 'tcx> {
-    pub(crate) cx: &'a mut core::DocContext<'tcx>,
+use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
+use rustc_middle::bug;
+use rustc_middle::ty::{self, Region, Ty};
+use rustc_span::def_id::DefId;
+use rustc_span::symbol::{kw, Symbol};
+use rustc_trait_selection::traits::auto_trait::{self, RegionTarget};
+
+use thin_vec::ThinVec;
+
+use crate::clean::{self, simplify, Lifetime};
+use crate::clean::{
+    clean_generic_param_def, clean_middle_ty, clean_predicate, clean_trait_ref_with_bindings,
+    clean_ty_generics,
+};
+use crate::core::DocContext;
+
+#[instrument(level = "debug", skip(cx))]
+pub(crate) fn synthesize_auto_trait_impls<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    item_def_id: DefId,
+) -> Vec<clean::Item> {
+    let tcx = cx.tcx;
+    let param_env = tcx.param_env(item_def_id);
+    let ty = tcx.type_of(item_def_id).instantiate_identity();
+
+    let finder = auto_trait::AutoTraitFinder::new(tcx);
+    let mut auto_trait_impls: Vec<_> = cx
+        .auto_traits
+        .clone()
+        .into_iter()
+        .filter_map(|trait_def_id| {
+            synthesize_auto_trait_impl(
+                cx,
+                ty,
+                trait_def_id,
+                param_env,
+                item_def_id,
+                &finder,
+                DiscardPositiveImpls::No,
+            )
+        })
+        .collect();
+    // We are only interested in case the type *doesn't* implement the `Sized` trait.
+    if !ty.is_sized(tcx, param_env)
+        && let Some(sized_trait_def_id) = tcx.lang_items().sized_trait()
+        && let Some(impl_item) = synthesize_auto_trait_impl(
+            cx,
+            ty,
+            sized_trait_def_id,
+            param_env,
+            item_def_id,
+            &finder,
+            DiscardPositiveImpls::Yes,
+        )
+    {
+        auto_trait_impls.push(impl_item);
+    }
+    auto_trait_impls
 }
 
-impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx>
-where
-    'tcx: 'a, // should be an implied bound; rustc bug #98852.
-{
-    pub(crate) fn new(cx: &'a mut core::DocContext<'tcx>) -> Self {
-        AutoTraitFinder { cx }
+#[instrument(level = "debug", skip(cx, finder))]
+fn synthesize_auto_trait_impl<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    ty: Ty<'tcx>,
+    trait_def_id: DefId,
+    param_env: ty::ParamEnv<'tcx>,
+    item_def_id: DefId,
+    finder: &auto_trait::AutoTraitFinder<'tcx>,
+    discard_positive_impls: DiscardPositiveImpls,
+) -> Option<clean::Item> {
+    let tcx = cx.tcx;
+    let trait_ref = ty::Binder::dummy(ty::TraitRef::new(tcx, trait_def_id, [ty]));
+    if !cx.generated_synthetics.insert((ty, trait_def_id)) {
+        debug!("already generated, aborting");
+        return None;
     }
 
-    fn generate_for_trait(
-        &mut self,
-        ty: Ty<'tcx>,
-        trait_def_id: DefId,
-        param_env: ty::ParamEnv<'tcx>,
-        item_def_id: DefId,
-        f: &auto_trait::AutoTraitFinder<'tcx>,
-        // If this is set, show only negative trait implementations, not positive ones.
-        discard_positive_impl: bool,
-    ) -> Option<Item> {
-        let tcx = self.cx.tcx;
-        let trait_ref = ty::Binder::dummy(ty::TraitRef::new(tcx, trait_def_id, [ty]));
-        if !self.cx.generated_synthetics.insert((ty, trait_def_id)) {
-            debug!("get_auto_trait_impl_for({trait_ref:?}): already generated, aborting");
-            return None;
-        }
+    let result = finder.find_auto_trait_generics(ty, param_env, trait_def_id, |info| {
+        clean_param_env(cx, item_def_id, info.full_user_env, info.region_data, info.vid_to_region)
+    });
 
-        let result = f.find_auto_trait_generics(ty, param_env, trait_def_id, |info| {
-            let region_data = info.region_data;
+    let (generics, polarity) = match result {
+        auto_trait::AutoTraitResult::PositiveImpl(generics) => {
+            if let DiscardPositiveImpls::Yes = discard_positive_impls {
+                return None;
+            }
 
-            let names_map = tcx
-                .generics_of(item_def_id)
-                .params
-                .iter()
-                .filter_map(|param| match param.kind {
-                    ty::GenericParamDefKind::Lifetime => Some(param.name),
-                    _ => None,
-                })
-                .map(|name| (name, Lifetime(name)))
-                .collect();
-            let lifetime_predicates = Self::handle_lifetimes(&region_data, &names_map);
-            let new_generics = self.param_env_to_generics(
-                item_def_id,
-                info.full_user_env,
-                lifetime_predicates,
-                info.vid_to_region,
+            (generics, ty::ImplPolarity::Positive)
+        }
+        auto_trait::AutoTraitResult::NegativeImpl => {
+            // For negative impls, we use the generic params, but *not* the predicates,
+            // from the original type. Otherwise, the displayed impl appears to be a
+            // conditional negative impl, when it's really unconditional.
+            //
+            // For example, consider the struct Foo<T: Copy>(*mut T). Using
+            // the original predicates in our impl would cause us to generate
+            // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
+            // implements Send where T is not copy.
+            //
+            // Instead, we generate `impl !Send for Foo<T>`, which better
+            // expresses the fact that `Foo<T>` never implements `Send`,
+            // regardless of the choice of `T`.
+            let mut generics = clean_ty_generics(
+                cx,
+                tcx.generics_of(item_def_id),
+                ty::GenericPredicates::default(),
             );
+            generics.where_predicates.clear();
 
-            debug!(
-                "find_auto_trait_generics(item_def_id={:?}, trait_def_id={:?}): \
-                    finished with {:?}",
-                item_def_id, trait_def_id, new_generics
-            );
+            (generics, ty::ImplPolarity::Negative)
+        }
+        auto_trait::AutoTraitResult::ExplicitImpl => return None,
+    };
+
+    Some(clean::Item {
+        name: None,
+        attrs: Default::default(),
+        item_id: clean::ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
+        kind: Box::new(clean::ImplItem(Box::new(clean::Impl {
+            unsafety: hir::Unsafety::Normal,
+            generics,
+            trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref, ThinVec::new())),
+            for_: clean_middle_ty(ty::Binder::dummy(ty), cx, None, None),
+            items: Vec::new(),
+            polarity,
+            kind: clean::ImplKind::Auto,
+        }))),
+        cfg: None,
+        inline_stmt_id: None,
+    })
+}
 
-            new_generics
-        });
+#[derive(Debug)]
+enum DiscardPositiveImpls {
+    Yes,
+    No,
+}
 
-        let polarity;
-        let new_generics = match result {
-            AutoTraitResult::PositiveImpl(new_generics) => {
-                polarity = ty::ImplPolarity::Positive;
-                if discard_positive_impl {
-                    return None;
+#[instrument(level = "debug", skip(cx, region_data, vid_to_region))]
+fn clean_param_env<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    item_def_id: DefId,
+    param_env: ty::ParamEnv<'tcx>,
+    region_data: RegionConstraintData<'tcx>,
+    vid_to_region: FxIndexMap<ty::RegionVid, ty::Region<'tcx>>,
+) -> clean::Generics {
+    let tcx = cx.tcx;
+    let generics = tcx.generics_of(item_def_id);
+
+    let params: ThinVec<_> = generics
+        .params
+        .iter()
+        .inspect(|param| {
+            if cfg!(debug_assertions) {
+                debug_assert!(!param.is_anonymous_lifetime() && !param.is_host_effect());
+                if let ty::GenericParamDefKind::Type { synthetic, .. } = param.kind {
+                    debug_assert!(!synthetic && param.name != kw::SelfUpper);
                 }
-                new_generics
             }
-            AutoTraitResult::NegativeImpl => {
-                polarity = ty::ImplPolarity::Negative;
-
-                // For negative impls, we use the generic params, but *not* the predicates,
-                // from the original type. Otherwise, the displayed impl appears to be a
-                // conditional negative impl, when it's really unconditional.
-                //
-                // For example, consider the struct Foo<T: Copy>(*mut T). Using
-                // the original predicates in our impl would cause us to generate
-                // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
-                // implements Send where T is not copy.
-                //
-                // Instead, we generate `impl !Send for Foo<T>`, which better
-                // expresses the fact that `Foo<T>` never implements `Send`,
-                // regardless of the choice of `T`.
-                let raw_generics = clean_ty_generics(
-                    self.cx,
-                    tcx.generics_of(item_def_id),
-                    ty::GenericPredicates::default(),
-                );
-                let params = raw_generics.params;
-
-                Generics { params, where_predicates: ThinVec::new() }
-            }
-            AutoTraitResult::ExplicitImpl => return None,
-        };
-
-        Some(Item {
-            name: None,
-            attrs: Default::default(),
-            item_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
-            kind: Box::new(ImplItem(Box::new(Impl {
-                unsafety: hir::Unsafety::Normal,
-                generics: new_generics,
-                trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, ThinVec::new())),
-                for_: clean_middle_ty(ty::Binder::dummy(ty), self.cx, None, None),
-                items: Vec::new(),
-                polarity,
-                kind: ImplKind::Auto,
-            }))),
-            cfg: None,
-            inline_stmt_id: None,
         })
-    }
-
-    pub(crate) fn get_auto_trait_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
-        let tcx = self.cx.tcx;
-        let param_env = tcx.param_env(item_def_id);
-        let ty = tcx.type_of(item_def_id).instantiate_identity();
-        let f = auto_trait::AutoTraitFinder::new(tcx);
-
-        debug!("get_auto_trait_impls({ty:?})");
-        let auto_traits: Vec<_> = self.cx.auto_traits.to_vec();
-        let mut auto_traits: Vec<Item> = auto_traits
-            .into_iter()
-            .filter_map(|trait_def_id| {
-                self.generate_for_trait(ty, trait_def_id, param_env, item_def_id, &f, false)
-            })
-            .collect();
-        // We are only interested in case the type *doesn't* implement the Sized trait.
-        if !ty.is_sized(tcx, param_env) {
-            // In case `#![no_core]` is used, `sized_trait` returns nothing.
-            if let Some(item) = tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
-                self.generate_for_trait(ty, sized_trait_did, param_env, item_def_id, &f, true)
-            }) {
-                auto_traits.push(item);
-            }
-        }
-        auto_traits
-    }
-
-    fn get_lifetime(region: Region<'_>, names_map: &FxHashMap<Symbol, Lifetime>) -> Lifetime {
-        region_name(region)
-            .map(|name| {
-                names_map
-                    .get(&name)
-                    .unwrap_or_else(|| panic!("Missing lifetime with name {name:?} for {region:?}"))
+        // We're basing the generics of the synthetic auto trait impl off of the generics of the
+        // implementing type. Its generic parameters may have defaults, don't copy them over:
+        // Generic parameter defaults are meaningless in impls.
+        .map(|param| clean_generic_param_def(param, clean::ParamDefaults::No, cx))
+        .collect();
+
+    // FIXME(#111101): Incorporate the explicit predicates of the item here...
+    let item_predicates: FxIndexSet<_> =
+        tcx.predicates_of(item_def_id).predicates.iter().map(|(pred, _)| pred).collect();
+    let where_predicates = param_env
+        .caller_bounds()
+        .iter()
+        // FIXME: ...which hopefully allows us to simplify this:
+        .filter(|pred| {
+            !item_predicates.contains(pred)
+                || pred
+                    .as_trait_clause()
+                    .is_some_and(|pred| tcx.lang_items().sized_trait() == Some(pred.def_id()))
+        })
+        .map(|pred| {
+            tcx.fold_regions(pred, |r, _| match *r {
+                // FIXME: Don't `unwrap_or`, I think we should panic if we encounter an infer var that
+                // we can't map to a concrete region. However, `AutoTraitFinder` *does* leak those kinds
+                // of `ReVar`s for some reason at the time of writing. See `rustdoc-ui/` tests.
+                // This is in dire need of an investigation into `AutoTraitFinder`.
+                ty::ReVar(vid) => vid_to_region.get(&vid).copied().unwrap_or(r),
+                ty::ReEarlyParam(_) | ty::ReStatic | ty::ReBound(..) | ty::ReError(_) => r,
+                // FIXME(#120606): `AutoTraitFinder` can actually leak placeholder regions which feels
+                // incorrect. Needs investigation.
+                ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReErased => {
+                    bug!("unexpected region kind: {r:?}")
+                }
             })
-            .unwrap_or(&Lifetime::statik())
-            .clone()
-    }
-
-    /// This method calculates two things: Lifetime constraints of the form `'a: 'b`,
-    /// and region constraints of the form `RegionVid: 'a`
-    ///
-    /// This is essentially a simplified version of lexical_region_resolve. However,
-    /// handle_lifetimes determines what *needs be* true in order for an impl to hold.
-    /// lexical_region_resolve, along with much of the rest of the compiler, is concerned
-    /// with determining if a given set up constraints/predicates *are* met, given some
-    /// starting conditions (e.g., user-provided code). For this reason, it's easier
-    /// to perform the calculations we need on our own, rather than trying to make
-    /// existing inference/solver code do what we want.
-    fn handle_lifetimes<'cx>(
-        regions: &RegionConstraintData<'cx>,
-        names_map: &FxHashMap<Symbol, Lifetime>,
-    ) -> ThinVec<WherePredicate> {
-        // Our goal is to 'flatten' the list of constraints by eliminating
-        // all intermediate RegionVids. At the end, all constraints should
-        // be between Regions (aka region variables). This gives us the information
-        // we need to create the Generics.
-        let mut finished: FxHashMap<_, Vec<_>> = Default::default();
-
-        let mut vid_map: FxHashMap<RegionTarget<'_>, RegionDeps<'_>> = Default::default();
-
-        // Flattening is done in two parts. First, we insert all of the constraints
-        // into a map. Each RegionTarget (either a RegionVid or a Region) maps
-        // to its smaller and larger regions. Note that 'larger' regions correspond
-        // to sub-regions in Rust code (e.g., in 'a: 'b, 'a is the larger region).
-        for (constraint, _) in &regions.constraints {
-            match *constraint {
-                Constraint::VarSubVar(r1, r2) => {
-                    {
-                        let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default();
-                        deps1.larger.insert(RegionTarget::RegionVid(r2));
-                    }
+        })
+        .flat_map(|pred| clean_predicate(pred, cx))
+        .chain(clean_region_outlives_constraints(&region_data, generics))
+        .collect();
+
+    let mut generics = clean::Generics { params, where_predicates };
+    simplify::sized_bounds(cx, &mut generics);
+    generics.where_predicates = simplify::where_clauses(cx, generics.where_predicates);
+    generics
+}
 
-                    let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default();
-                    deps2.smaller.insert(RegionTarget::RegionVid(r1));
-                }
-                Constraint::RegSubVar(region, vid) => {
-                    let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
-                    deps.smaller.insert(RegionTarget::Region(region));
-                }
-                Constraint::VarSubReg(vid, region) => {
-                    let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
-                    deps.larger.insert(RegionTarget::Region(region));
-                }
-                Constraint::RegSubReg(r1, r2) => {
-                    // The constraint is already in the form that we want, so we're done with it
-                    // Desired order is 'larger, smaller', so flip then
-                    if region_name(r1) != region_name(r2) {
-                        finished
-                            .entry(region_name(r2).expect("no region_name found"))
-                            .or_default()
-                            .push(r1);
-                    }
-                }
+/// Clean region outlives constraints to where-predicates.
+///
+/// This is essentially a simplified version of `lexical_region_resolve`.
+///
+/// However, here we determine what *needs to be* true in order for an impl to hold.
+/// `lexical_region_resolve`, along with much of the rest of the compiler, is concerned
+/// with determining if a given set up constraints / predicates *are* met, given some
+/// starting conditions like user-provided code.
+///
+/// For this reason, it's easier to perform the calculations we need on our own,
+/// rather than trying to make existing inference/solver code do what we want.
+fn clean_region_outlives_constraints<'tcx>(
+    regions: &RegionConstraintData<'tcx>,
+    generics: &'tcx ty::Generics,
+) -> ThinVec<clean::WherePredicate> {
+    // Our goal is to "flatten" the list of constraints by eliminating all intermediate
+    // `RegionVids` (region inference variables). At the end, all constraints should be
+    // between `Region`s. This gives us the information we need to create the where-predicates.
+    // This flattening is done in two parts.
+
+    let mut outlives_predicates = FxIndexMap::<_, Vec<_>>::default();
+    let mut map = FxIndexMap::<RegionTarget<'_>, auto_trait::RegionDeps<'_>>::default();
+
+    // (1)  We insert all of the constraints into a map.
+    // Each `RegionTarget` (a `RegionVid` or a `Region`) maps to its smaller and larger regions.
+    // Note that "larger" regions correspond to sub regions in the surface language.
+    // E.g., in `'a: 'b`, `'a` is the larger region.
+    for (constraint, _) in &regions.constraints {
+        match *constraint {
+            Constraint::VarSubVar(vid1, vid2) => {
+                let deps1 = map.entry(RegionTarget::RegionVid(vid1)).or_default();
+                deps1.larger.insert(RegionTarget::RegionVid(vid2));
+
+                let deps2 = map.entry(RegionTarget::RegionVid(vid2)).or_default();
+                deps2.smaller.insert(RegionTarget::RegionVid(vid1));
             }
-        }
-
-        // Here, we 'flatten' the map one element at a time.
-        // All of the element's sub and super regions are connected
-        // to each other. For example, if we have a graph that looks like this:
-        //
-        // (A, B) - C - (D, E)
-        // Where (A, B) are subregions, and (D,E) are super-regions
-        //
-        // then after deleting 'C', the graph will look like this:
-        //  ... - A - (D, E ...)
-        //  ... - B - (D, E, ...)
-        //  (A, B, ...) - D - ...
-        //  (A, B, ...) - E - ...
-        //
-        //  where '...' signifies the existing sub and super regions of an entry
-        //  When two adjacent ty::Regions are encountered, we've computed a final
-        //  constraint, and add it to our list. Since we make sure to never re-add
-        //  deleted items, this process will always finish.
-        while !vid_map.is_empty() {
-            let target = *vid_map.keys().next().expect("Keys somehow empty");
-            let deps = vid_map.remove(&target).expect("Entry somehow missing");
-
-            for smaller in deps.smaller.iter() {
-                for larger in deps.larger.iter() {
-                    match (smaller, larger) {
-                        (&RegionTarget::Region(r1), &RegionTarget::Region(r2)) => {
-                            if region_name(r1) != region_name(r2) {
-                                finished
-                                    .entry(region_name(r2).expect("no region name found"))
-                                    .or_default()
-                                    .push(r1) // Larger, smaller
-                            }
-                        }
-                        (&RegionTarget::RegionVid(_), &RegionTarget::Region(_)) => {
-                            if let Entry::Occupied(v) = vid_map.entry(*smaller) {
-                                let smaller_deps = v.into_mut();
-                                smaller_deps.larger.insert(*larger);
-                                smaller_deps.larger.remove(&target);
-                            }
-                        }
-                        (&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => {
-                            if let Entry::Occupied(v) = vid_map.entry(*larger) {
-                                let deps = v.into_mut();
-                                deps.smaller.insert(*smaller);
-                                deps.smaller.remove(&target);
-                            }
-                        }
-                        (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => {
-                            if let Entry::Occupied(v) = vid_map.entry(*smaller) {
-                                let smaller_deps = v.into_mut();
-                                smaller_deps.larger.insert(*larger);
-                                smaller_deps.larger.remove(&target);
-                            }
-
-                            if let Entry::Occupied(v) = vid_map.entry(*larger) {
-                                let larger_deps = v.into_mut();
-                                larger_deps.smaller.insert(*smaller);
-                                larger_deps.smaller.remove(&target);
-                            }
-                        }
-                    }
+            Constraint::RegSubVar(region, vid) => {
+                let deps = map.entry(RegionTarget::RegionVid(vid)).or_default();
+                deps.smaller.insert(RegionTarget::Region(region));
+            }
+            Constraint::VarSubReg(vid, region) => {
+                let deps = map.entry(RegionTarget::RegionVid(vid)).or_default();
+                deps.larger.insert(RegionTarget::Region(region));
+            }
+            Constraint::RegSubReg(r1, r2) => {
+                // The constraint is already in the form that we want, so we're done with it
+                // The desired order is [larger, smaller], so flip them.
+                if early_bound_region_name(r1) != early_bound_region_name(r2) {
+                    outlives_predicates
+                        .entry(early_bound_region_name(r2).expect("no region_name found"))
+                        .or_default()
+                        .push(r1);
                 }
             }
         }
-
-        let lifetime_predicates = names_map
-            .iter()
-            .flat_map(|(name, lifetime)| {
-                let empty = Vec::new();
-                let bounds: FxHashSet<GenericBound> = finished
-                    .get(name)
-                    .unwrap_or(&empty)
-                    .iter()
-                    .map(|region| GenericBound::Outlives(Self::get_lifetime(*region, names_map)))
-                    .collect();
-
-                if bounds.is_empty() {
-                    return None;
-                }
-                Some(WherePredicate::RegionPredicate {
-                    lifetime: lifetime.clone(),
-                    bounds: bounds.into_iter().collect(),
-                })
-            })
-            .collect();
-
-        lifetime_predicates
     }
 
-    fn extract_for_generics(&self, pred: ty::Clause<'tcx>) -> FxHashSet<GenericParamDef> {
-        let bound_predicate = pred.kind();
-        let tcx = self.cx.tcx;
-        let regions =
-            match bound_predicate.skip_binder() {
-                ty::ClauseKind::Trait(poly_trait_pred) => tcx
-                    .collect_referenced_late_bound_regions(bound_predicate.rebind(poly_trait_pred)),
-                ty::ClauseKind::Projection(poly_proj_pred) => tcx
-                    .collect_referenced_late_bound_regions(bound_predicate.rebind(poly_proj_pred)),
-                _ => return FxHashSet::default(),
-            };
-
-        regions
-            .into_iter()
-            .filter_map(|br| {
-                match br {
-                    // We only care about named late bound regions, as we need to add them
-                    // to the 'for<>' section
-                    ty::BrNamed(def_id, name) => Some(GenericParamDef::lifetime(def_id, name)),
-                    _ => None,
-                }
-            })
-            .collect()
-    }
-
-    fn make_final_bounds(
-        &self,
-        ty_to_bounds: FxHashMap<Type, FxHashSet<GenericBound>>,
-        ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)>,
-        lifetime_to_bounds: FxHashMap<Lifetime, FxHashSet<GenericBound>>,
-    ) -> Vec<WherePredicate> {
-        ty_to_bounds
-            .into_iter()
-            .flat_map(|(ty, mut bounds)| {
-                if let Some((ref poly_trait, ref output)) = ty_to_fn.get(&ty) {
-                    let mut new_path = poly_trait.trait_.clone();
-                    let last_segment = new_path.segments.pop().expect("segments were empty");
-
-                    let (old_input, old_output) = match last_segment.args {
-                        GenericArgs::AngleBracketed { args, .. } => {
-                            let types = args
-                                .iter()
-                                .filter_map(|arg| match arg {
-                                    GenericArg::Type(ty) => Some(ty.clone()),
-                                    _ => None,
-                                })
-                                .collect();
-                            (types, None)
+    // (2)  Here, we "flatten" the map one element at a time. All of the elements' sub and super
+    // regions are connected to each other. For example, if we have a graph that looks like this:
+    //
+    //     (A, B) - C - (D, E)
+    //
+    // where (A, B) are sub regions, and (D,E) are super regions.
+    // Then, after deleting 'C', the graph will look like this:
+    //
+    //             ... - A - (D, E, ...)
+    //             ... - B - (D, E, ...)
+    //     (A, B, ...) - D - ...
+    //     (A, B, ...) - E - ...
+    //
+    // where '...' signifies the existing sub and super regions of an entry. When two adjacent
+    // `Region`s are encountered, we've computed a final constraint, and add it to our list.
+    // Since we make sure to never re-add deleted items, this process will always finish.
+    while !map.is_empty() {
+        let target = *map.keys().next().unwrap();
+        let deps = map.swap_remove(&target).unwrap();
+
+        for smaller in &deps.smaller {
+            for larger in &deps.larger {
+                match (smaller, larger) {
+                    (&RegionTarget::Region(smaller), &RegionTarget::Region(larger)) => {
+                        if early_bound_region_name(smaller) != early_bound_region_name(larger) {
+                            outlives_predicates
+                                .entry(
+                                    early_bound_region_name(larger).expect("no region name found"),
+                                )
+                                .or_default()
+                                .push(smaller)
                         }
-                        GenericArgs::Parenthesized { inputs, output } => (inputs, output),
-                    };
-
-                    let output = output.as_ref().cloned().map(Box::new);
-                    if old_output.is_some() && old_output != output {
-                        panic!("Output mismatch for {ty:?} {old_output:?} {output:?}");
-                    }
-
-                    let new_params = GenericArgs::Parenthesized { inputs: old_input, output };
-
-                    new_path
-                        .segments
-                        .push(PathSegment { name: last_segment.name, args: new_params });
-
-                    bounds.insert(GenericBound::TraitBound(
-                        PolyTrait {
-                            trait_: new_path,
-                            generic_params: poly_trait.generic_params.clone(),
-                        },
-                        hir::TraitBoundModifier::None,
-                    ));
-                }
-                if bounds.is_empty() {
-                    return None;
-                }
-
-                let mut bounds_vec = bounds.into_iter().collect();
-                self.sort_where_bounds(&mut bounds_vec);
-
-                Some(WherePredicate::BoundPredicate {
-                    ty,
-                    bounds: bounds_vec,
-                    bound_params: Vec::new(),
-                })
-            })
-            .chain(lifetime_to_bounds.into_iter().filter(|(_, bounds)| !bounds.is_empty()).map(
-                |(lifetime, bounds)| {
-                    let mut bounds_vec = bounds.into_iter().collect();
-                    self.sort_where_bounds(&mut bounds_vec);
-                    WherePredicate::RegionPredicate { lifetime, bounds: bounds_vec }
-                },
-            ))
-            .collect()
-    }
-
-    /// Converts the calculated `ParamEnv` and lifetime information to a [`clean::Generics`](Generics), suitable for
-    /// display on the docs page. Cleaning the `Predicates` produces sub-optimal [`WherePredicate`]s,
-    /// so we fix them up:
-    ///
-    /// * Multiple bounds for the same type are coalesced into one: e.g., `T: Copy`, `T: Debug`
-    /// becomes `T: Copy + Debug`
-    /// * `Fn` bounds are handled specially - instead of leaving it as `T: Fn(), <T as Fn::Output> =
-    /// K`, we use the dedicated syntax `T: Fn() -> K`
-    /// * We explicitly add a `?Sized` bound if we didn't find any `Sized` predicates for a type
-    fn param_env_to_generics(
-        &mut self,
-        item_def_id: DefId,
-        param_env: ty::ParamEnv<'tcx>,
-        mut existing_predicates: ThinVec<WherePredicate>,
-        vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'tcx>>,
-    ) -> Generics {
-        debug!(
-            "param_env_to_generics(item_def_id={:?}, param_env={:?}, \
-             existing_predicates={:?})",
-            item_def_id, param_env, existing_predicates
-        );
-
-        let tcx = self.cx.tcx;
-
-        // The `Sized` trait must be handled specially, since we only display it when
-        // it is *not* required (i.e., '?Sized')
-        let sized_trait = tcx.require_lang_item(LangItem::Sized, None);
-
-        let mut replacer = RegionReplacer { vid_to_region: &vid_to_region, tcx };
-
-        let orig_bounds: FxHashSet<_> = tcx.param_env(item_def_id).caller_bounds().iter().collect();
-        let clean_where_predicates = param_env
-            .caller_bounds()
-            .iter()
-            .filter(|p| {
-                !orig_bounds.contains(p)
-                    || match p.kind().skip_binder() {
-                        ty::ClauseKind::Trait(pred) => pred.def_id() == sized_trait,
-                        _ => false,
-                    }
-            })
-            .map(|p| p.fold_with(&mut replacer));
-
-        let raw_generics = clean_ty_generics(
-            self.cx,
-            tcx.generics_of(item_def_id),
-            tcx.explicit_predicates_of(item_def_id),
-        );
-        let mut generic_params = raw_generics.params;
-
-        debug!("param_env_to_generics({item_def_id:?}): generic_params={generic_params:?}");
-
-        let mut has_sized = FxHashSet::default();
-        let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default();
-        let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default();
-        let mut ty_to_traits: FxHashMap<Type, FxHashSet<Path>> = Default::default();
-
-        let mut ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)> = Default::default();
-
-        // FIXME: This code shares much of the logic found in `clean_ty_generics` and
-        //        `simplify::where_clause`. Consider deduplicating it to avoid diverging
-        //        implementations.
-        //        Further, the code below does not merge (partially re-sugared) bounds like
-        //        `Tr<A = T>` & `Tr<B = U>` and it does not render higher-ranked parameters
-        //        originating from equality predicates.
-        for p in clean_where_predicates {
-            let (orig_p, p) = (p, clean_predicate(p, self.cx));
-            if p.is_none() {
-                continue;
-            }
-            let p = p.unwrap();
-            match p {
-                WherePredicate::BoundPredicate { ty, mut bounds, .. } => {
-                    // Writing a projection trait bound of the form
-                    // <T as Trait>::Name : ?Sized
-                    // is illegal, because ?Sized bounds can only
-                    // be written in the (here, nonexistent) definition
-                    // of the type.
-                    // Therefore, we make sure that we never add a ?Sized
-                    // bound for projections
-                    if let Type::QPath { .. } = ty {
-                        has_sized.insert(ty.clone());
                     }
-
-                    if bounds.is_empty() {
-                        continue;
-                    }
-
-                    let mut for_generics = self.extract_for_generics(orig_p);
-
-                    assert!(bounds.len() == 1);
-                    let mut b = bounds.pop().expect("bounds were empty");
-
-                    if b.is_sized_bound(self.cx) {
-                        has_sized.insert(ty.clone());
-                    } else if !b
-                        .get_trait_path()
-                        .and_then(|trait_| {
-                            ty_to_traits
-                                .get(&ty)
-                                .map(|bounds| bounds.contains(&strip_path_generics(trait_)))
-                        })
-                        .unwrap_or(false)
-                    {
-                        // If we've already added a projection bound for the same type, don't add
-                        // this, as it would be a duplicate
-
-                        // Handle any 'Fn/FnOnce/FnMut' bounds specially,
-                        // as we want to combine them with any 'Output' qpaths
-                        // later
-
-                        let is_fn = match b {
-                            GenericBound::TraitBound(ref mut p, _) => {
-                                // Insert regions into the for_generics hash map first, to ensure
-                                // that we don't end up with duplicate bounds (e.g., for<'b, 'b>)
-                                for_generics.extend(p.generic_params.drain(..));
-                                p.generic_params.extend(for_generics);
-                                self.is_fn_trait(&p.trait_)
-                            }
-                            _ => false,
-                        };
-
-                        let poly_trait = b.get_poly_trait().expect("Cannot get poly trait");
-
-                        if is_fn {
-                            ty_to_fn
-                                .entry(ty.clone())
-                                .and_modify(|e| *e = (poly_trait.clone(), e.1.clone()))
-                                .or_insert(((poly_trait.clone()), None));
-
-                            ty_to_bounds.entry(ty.clone()).or_default();
-                        } else {
-                            ty_to_bounds.entry(ty.clone()).or_default().insert(b.clone());
+                    (&RegionTarget::RegionVid(_), &RegionTarget::Region(_)) => {
+                        if let IndexEntry::Occupied(v) = map.entry(*smaller) {
+                            let smaller_deps = v.into_mut();
+                            smaller_deps.larger.insert(*larger);
+                            smaller_deps.larger.swap_remove(&target);
                         }
                     }
-                }
-                WherePredicate::RegionPredicate { lifetime, bounds } => {
-                    lifetime_to_bounds.entry(lifetime).or_default().extend(bounds);
-                }
-                WherePredicate::EqPredicate { lhs, rhs } => {
-                    match lhs {
-                        Type::QPath(box QPathData {
-                            ref assoc,
-                            ref self_type,
-                            trait_: Some(ref trait_),
-                            ..
-                        }) => {
-                            let ty = &*self_type;
-                            let mut new_trait = trait_.clone();
-
-                            if self.is_fn_trait(trait_) && assoc.name == sym::Output {
-                                ty_to_fn
-                                    .entry(ty.clone())
-                                    .and_modify(|e| {
-                                        *e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
-                                    })
-                                    .or_insert((
-                                        PolyTrait {
-                                            trait_: trait_.clone(),
-                                            generic_params: Vec::new(),
-                                        },
-                                        Some(rhs.ty().unwrap().clone()),
-                                    ));
-                                continue;
-                            }
-
-                            let args = &mut new_trait
-                                .segments
-                                .last_mut()
-                                .expect("segments were empty")
-                                .args;
-
-                            match args {
-                                // Convert something like '<T as Iterator::Item> = u8'
-                                // to 'T: Iterator<Item=u8>'
-                                GenericArgs::AngleBracketed { ref mut bindings, .. } => {
-                                    bindings.push(TypeBinding {
-                                        assoc: assoc.clone(),
-                                        kind: TypeBindingKind::Equality { term: rhs },
-                                    });
-                                }
-                                GenericArgs::Parenthesized { .. } => {
-                                    existing_predicates.push(WherePredicate::EqPredicate {
-                                        lhs: lhs.clone(),
-                                        rhs,
-                                    });
-                                    continue; // If something other than a Fn ends up
-                                    // with parentheses, leave it alone
-                                }
-                            }
-
-                            let bounds = ty_to_bounds.entry(ty.clone()).or_default();
-
-                            bounds.insert(GenericBound::TraitBound(
-                                PolyTrait { trait_: new_trait, generic_params: Vec::new() },
-                                hir::TraitBoundModifier::None,
-                            ));
-
-                            // Remove any existing 'plain' bound (e.g., 'T: Iterator`) so
-                            // that we don't see a
-                            // duplicate bound like `T: Iterator + Iterator<Item=u8>`
-                            // on the docs page.
-                            bounds.remove(&GenericBound::TraitBound(
-                                PolyTrait { trait_: trait_.clone(), generic_params: Vec::new() },
-                                hir::TraitBoundModifier::None,
-                            ));
-                            // Avoid creating any new duplicate bounds later in the outer
-                            // loop
-                            ty_to_traits.entry(ty.clone()).or_default().insert(trait_.clone());
+                    (&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => {
+                        if let IndexEntry::Occupied(v) = map.entry(*larger) {
+                            let deps = v.into_mut();
+                            deps.smaller.insert(*smaller);
+                            deps.smaller.swap_remove(&target);
                         }
-                        _ => panic!("Unexpected LHS {lhs:?} for {item_def_id:?}"),
                     }
-                }
-            };
-        }
-
-        let final_bounds = self.make_final_bounds(ty_to_bounds, ty_to_fn, lifetime_to_bounds);
-
-        existing_predicates.extend(final_bounds);
-
-        for param in generic_params.iter_mut() {
-            match param.kind {
-                GenericParamDefKind::Type { ref mut default, ref mut bounds, .. } => {
-                    // We never want something like `impl<T=Foo>`.
-                    default.take();
-                    let generic_ty = Type::Generic(param.name);
-                    if !has_sized.contains(&generic_ty) {
-                        bounds.insert(0, GenericBound::maybe_sized(self.cx));
+                    (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => {
+                        if let IndexEntry::Occupied(v) = map.entry(*smaller) {
+                            let smaller_deps = v.into_mut();
+                            smaller_deps.larger.insert(*larger);
+                            smaller_deps.larger.swap_remove(&target);
+                        }
+                        if let IndexEntry::Occupied(v) = map.entry(*larger) {
+                            let larger_deps = v.into_mut();
+                            larger_deps.smaller.insert(*smaller);
+                            larger_deps.smaller.swap_remove(&target);
+                        }
                     }
                 }
-                GenericParamDefKind::Lifetime { .. } => {}
-                GenericParamDefKind::Const { ref mut default, .. } => {
-                    // We never want something like `impl<const N: usize = 10>`
-                    default.take();
-                }
             }
         }
-
-        self.sort_where_predicates(&mut existing_predicates);
-
-        Generics { params: generic_params, where_predicates: existing_predicates }
-    }
-
-    /// Ensure that the predicates are in a consistent order. The precise
-    /// ordering doesn't actually matter, but it's important that
-    /// a given set of predicates always appears in the same order -
-    /// both for visual consistency between 'rustdoc' runs, and to
-    /// make writing tests much easier
-    #[inline]
-    fn sort_where_predicates(&self, predicates: &mut [WherePredicate]) {
-        // We should never have identical bounds - and if we do,
-        // they're visually identical as well. Therefore, using
-        // an unstable sort is fine.
-        self.unstable_debug_sort(predicates);
-    }
-
-    /// Ensure that the bounds are in a consistent order. The precise
-    /// ordering doesn't actually matter, but it's important that
-    /// a given set of bounds always appears in the same order -
-    /// both for visual consistency between 'rustdoc' runs, and to
-    /// make writing tests much easier
-    #[inline]
-    fn sort_where_bounds(&self, bounds: &mut Vec<GenericBound>) {
-        // We should never have identical bounds - and if we do,
-        // they're visually identical as well. Therefore, using
-        // an unstable sort is fine.
-        self.unstable_debug_sort(bounds);
     }
 
-    /// This might look horrendously hacky, but it's actually not that bad.
-    ///
-    /// For performance reasons, we use several different FxHashMaps
-    /// in the process of computing the final set of where predicates.
-    /// However, the iteration order of a HashMap is completely unspecified.
-    /// In fact, the iteration of an FxHashMap can even vary between platforms,
-    /// since FxHasher has different behavior for 32-bit and 64-bit platforms.
-    ///
-    /// Obviously, it's extremely undesirable for documentation rendering
-    /// to be dependent on the platform it's run on. Apart from being confusing
-    /// to end users, it makes writing tests much more difficult, as predicates
-    /// can appear in any order in the final result.
-    ///
-    /// To solve this problem, we sort WherePredicates and GenericBounds
-    /// by their Debug string. The thing to keep in mind is that we don't really
-    /// care what the final order is - we're synthesizing an impl or bound
-    /// ourselves, so any order can be considered equally valid. By sorting the
-    /// predicates and bounds, however, we ensure that for a given codebase, all
-    /// auto-trait impls always render in exactly the same way.
-    ///
-    /// Using the Debug implementation for sorting prevents us from needing to
-    /// write quite a bit of almost entirely useless code (e.g., how should two
-    /// Types be sorted relative to each other). It also allows us to solve the
-    /// problem for both WherePredicates and GenericBounds at the same time. This
-    /// approach is probably somewhat slower, but the small number of items
-    /// involved (impls rarely have more than a few bounds) means that it
-    /// shouldn't matter in practice.
-    fn unstable_debug_sort<T: Debug>(&self, vec: &mut [T]) {
-        vec.sort_by_cached_key(|x| format!("{x:?}"))
-    }
+    let region_params: FxIndexSet<_> = generics
+        .params
+        .iter()
+        .filter_map(|param| match param.kind {
+            ty::GenericParamDefKind::Lifetime => Some(param.name),
+            _ => None,
+        })
+        .collect();
 
-    fn is_fn_trait(&self, path: &Path) -> bool {
-        let tcx = self.cx.tcx;
-        let did = path.def_id();
-        did == tcx.require_lang_item(LangItem::Fn, None)
-            || did == tcx.require_lang_item(LangItem::FnMut, None)
-            || did == tcx.require_lang_item(LangItem::FnOnce, None)
-    }
+    region_params
+        .iter()
+        .filter_map(|&name| {
+            let bounds: FxIndexSet<_> = outlives_predicates
+                .get(&name)?
+                .iter()
+                .map(|&region| {
+                    let lifetime = early_bound_region_name(region)
+                        .inspect(|name| assert!(region_params.contains(name)))
+                        .map(|name| Lifetime(name))
+                        .unwrap_or(Lifetime::statik());
+                    clean::GenericBound::Outlives(lifetime)
+                })
+                .collect();
+            if bounds.is_empty() {
+                return None;
+            }
+            Some(clean::WherePredicate::RegionPredicate {
+                lifetime: Lifetime(name),
+                bounds: bounds.into_iter().collect(),
+            })
+        })
+        .collect()
 }
 
-fn region_name(region: Region<'_>) -> Option<Symbol> {
+fn early_bound_region_name(region: Region<'_>) -> Option<Symbol> {
     match *region {
         ty::ReEarlyParam(r) => Some(r.name),
         _ => None,
     }
 }
-
-/// Replaces all [`ty::RegionVid`]s in a type with [`ty::Region`]s, using the provided map.
-struct RegionReplacer<'a, 'tcx> {
-    vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>,
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for RegionReplacer<'a, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match *r {
-            // These are the regions that can be seen in the AST.
-            ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned().unwrap_or(r),
-            ty::ReEarlyParam(_) | ty::ReStatic | ty::ReBound(..) | ty::ReError(_) => r,
-            r => bug!("unexpected region: {r:?}"),
-        }
-    }
-}
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0cdf52bfb00..a25a506d9c5 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -21,10 +21,8 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
 use rustc_hir::PredicateOrigin;
 use rustc_hir_analysis::lower_ty;
-use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_middle::metadata::Reexport;
 use rustc_middle::middle::resolve_bound_vars as rbv;
-use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt};
@@ -35,9 +33,7 @@ use rustc_span::{self, ExpnKind};
 use rustc_trait_selection::traits::wf::object_region_bounds;
 
 use std::borrow::Cow;
-use std::collections::hash_map::Entry;
 use std::collections::BTreeMap;
-use std::hash::Hash;
 use std::mem;
 use thin_vec::ThinVec;
 
@@ -502,6 +498,7 @@ fn projection_to_path_segment<'tcx>(
 
 fn clean_generic_param_def<'tcx>(
     def: &ty::GenericParamDef,
+    defaults: ParamDefaults,
     cx: &mut DocContext<'tcx>,
 ) -> GenericParamDef {
     let (name, kind) = match def.kind {
@@ -509,7 +506,9 @@ fn clean_generic_param_def<'tcx>(
             (def.name, GenericParamDefKind::Lifetime { outlives: ThinVec::new() })
         }
         ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
-            let default = if has_default {
+            let default = if let ParamDefaults::Yes = defaults
+                && has_default
+            {
                 Some(clean_middle_ty(
                     ty::Binder::dummy(cx.tcx.type_of(def.def_id).instantiate_identity()),
                     cx,
@@ -542,11 +541,14 @@ fn clean_generic_param_def<'tcx>(
                     Some(def.def_id),
                     None,
                 )),
-                default: match has_default {
-                    true => Some(Box::new(
+                default: if let ParamDefaults::Yes = defaults
+                    && has_default
+                {
+                    Some(Box::new(
                         cx.tcx.const_param_default(def.def_id).instantiate_identity().to_string(),
-                    )),
-                    false => None,
+                    ))
+                } else {
+                    None
                 },
                 is_host_effect,
             },
@@ -556,6 +558,12 @@ fn clean_generic_param_def<'tcx>(
     GenericParamDef { name, def_id: def.def_id, kind }
 }
 
+/// Whether to clean generic parameter defaults or not.
+enum ParamDefaults {
+    Yes,
+    No,
+}
+
 fn clean_generic_param<'tcx>(
     cx: &mut DocContext<'tcx>,
     generics: Option<&hir::Generics<'tcx>>,
@@ -759,34 +767,30 @@ fn clean_ty_generics<'tcx>(
     gens: &ty::Generics,
     preds: ty::GenericPredicates<'tcx>,
 ) -> Generics {
-    // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
-    // since `Clean for ty::Predicate` would consume them.
+    // Don't populate `cx.impl_trait_bounds` before cleaning where clauses,
+    // since `clean_predicate` would consume them.
     let mut impl_trait = BTreeMap::<u32, Vec<GenericBound>>::default();
 
-    // Bounds in the type_params and lifetimes fields are repeated in the
-    // predicates field (see rustc_hir_analysis::collect::ty_generics), so remove
-    // them.
-    let stripped_params = gens
+    let params: ThinVec<_> = gens
         .params
         .iter()
-        .filter_map(|param| match param.kind {
-            ty::GenericParamDefKind::Lifetime if param.is_anonymous_lifetime() => None,
-            ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)),
+        .filter(|param| match param.kind {
+            ty::GenericParamDefKind::Lifetime => !param.is_anonymous_lifetime(),
             ty::GenericParamDefKind::Type { synthetic, .. } => {
                 if param.name == kw::SelfUpper {
-                    assert_eq!(param.index, 0);
-                    return None;
+                    debug_assert_eq!(param.index, 0);
+                    return false;
                 }
                 if synthetic {
                     impl_trait.insert(param.index, vec![]);
-                    return None;
+                    return false;
                 }
-                Some(clean_generic_param_def(param, cx))
+                true
             }
-            ty::GenericParamDefKind::Const { is_host_effect: true, .. } => None,
-            ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)),
+            ty::GenericParamDefKind::Const { is_host_effect, .. } => !is_host_effect,
         })
-        .collect::<ThinVec<GenericParamDef>>();
+        .map(|param| clean_generic_param_def(param, ParamDefaults::Yes, cx))
+        .collect();
 
     // param index -> [(trait DefId, associated type name & generics, term)]
     let mut impl_trait_proj =
@@ -882,56 +886,13 @@ fn clean_ty_generics<'tcx>(
 
     // Now that `cx.impl_trait_bounds` is populated, we can process
     // remaining predicates which could contain `impl Trait`.
-    let mut where_predicates =
-        where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::<Vec<_>>();
-
-    // In the surface language, all type parameters except `Self` have an
-    // implicit `Sized` bound unless removed with `?Sized`.
-    // However, in the list of where-predicates below, `Sized` appears like a
-    // normal bound: It's either present (the type is sized) or
-    // absent (the type might be unsized) but never *maybe* (i.e. `?Sized`).
-    //
-    // This is unsuitable for rendering.
-    // Thus, as a first step remove all `Sized` bounds that should be implicit.
-    //
-    // Note that associated types also have an implicit `Sized` bound but we
-    // don't actually know the set of associated types right here so that's
-    // handled when cleaning associated types.
-    let mut sized_params = FxHashSet::default();
-    where_predicates.retain(|pred| {
-        if let WherePredicate::BoundPredicate { ty: Generic(g), bounds, .. } = pred
-            && *g != kw::SelfUpper
-            && bounds.iter().any(|b| b.is_sized_bound(cx))
-        {
-            sized_params.insert(*g);
-            false
-        } else {
-            true
-        }
-    });
-
-    // As a final step, go through the type parameters again and insert a
-    // `?Sized` bound for each one we didn't find to be `Sized`.
-    for tp in &stripped_params {
-        if let types::GenericParamDefKind::Type { .. } = tp.kind
-            && !sized_params.contains(&tp.name)
-        {
-            where_predicates.push(WherePredicate::BoundPredicate {
-                ty: Type::Generic(tp.name),
-                bounds: vec![GenericBound::maybe_sized(cx)],
-                bound_params: Vec::new(),
-            })
-        }
-    }
-
-    // It would be nice to collect all of the bounds on a type and recombine
-    // them if possible, to avoid e.g., `where T: Foo, T: Bar, T: Sized, T: 'a`
-    // and instead see `where T: Foo + Bar + Sized + 'a`
+    let where_predicates =
+        where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect();
 
-    Generics {
-        params: stripped_params,
-        where_predicates: simplify::where_clauses(cx, where_predicates),
-    }
+    let mut generics = Generics { params, where_predicates };
+    simplify::sized_bounds(cx, &mut generics);
+    generics.where_predicates = simplify::where_clauses(cx, generics.where_predicates);
+    generics
 }
 
 fn clean_ty_alias_inner_type<'tcx>(
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index c35fb9ec788..5a3ccb6239a 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -12,6 +12,7 @@
 //! bounds by special casing scenarios such as these. Fun!
 
 use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::unord::UnordSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty;
 use thin_vec::ThinVec;
@@ -21,7 +22,7 @@ use crate::clean::GenericArgs as PP;
 use crate::clean::WherePredicate as WP;
 use crate::core::DocContext;
 
-pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> ThinVec<WP> {
+pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: ThinVec<WP>) -> ThinVec<WP> {
     // First, partition the where clause into its separate components.
     //
     // We use `FxIndexMap` so that the insertion order is preserved to prevent messing up to
@@ -128,6 +129,48 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId)
         .any(|did| trait_is_same_or_supertrait(cx, did, trait_))
 }
 
+pub(crate) fn sized_bounds(cx: &mut DocContext<'_>, generics: &mut clean::Generics) {
+    let mut sized_params = UnordSet::new();
+
+    // In the surface language, all type parameters except `Self` have an
+    // implicit `Sized` bound unless removed with `?Sized`.
+    // However, in the list of where-predicates below, `Sized` appears like a
+    // normal bound: It's either present (the type is sized) or
+    // absent (the type might be unsized) but never *maybe* (i.e. `?Sized`).
+    //
+    // This is unsuitable for rendering.
+    // Thus, as a first step remove all `Sized` bounds that should be implicit.
+    //
+    // Note that associated types also have an implicit `Sized` bound but we
+    // don't actually know the set of associated types right here so that
+    // should be handled when cleaning associated types.
+    generics.where_predicates.retain(|pred| {
+        if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred
+            && *param != rustc_span::symbol::kw::SelfUpper
+            && bounds.iter().any(|b| b.is_sized_bound(cx))
+        {
+            sized_params.insert(*param);
+            false
+        } else {
+            true
+        }
+    });
+
+    // As a final step, go through the type parameters again and insert a
+    // `?Sized` bound for each one we didn't find to be `Sized`.
+    for param in &generics.params {
+        if let clean::GenericParamDefKind::Type { .. } = param.kind
+            && !sized_params.contains(&param.name)
+        {
+            generics.where_predicates.push(WP::BoundPredicate {
+                ty: clean::Type::Generic(param.name),
+                bounds: vec![clean::GenericBound::maybe_sized(cx)],
+                bound_params: Vec::new(),
+            })
+        }
+    }
+}
+
 /// Move bounds that are (likely) directly attached to generic parameters from the where-clause to
 /// the respective parameter.
 ///
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index a51f6360df2..6793ea9f485 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1277,13 +1277,6 @@ impl GenericBound {
         false
     }
 
-    pub(crate) fn get_poly_trait(&self) -> Option<PolyTrait> {
-        if let GenericBound::TraitBound(ref p, _) = *self {
-            return Some(p.clone());
-        }
-        None
-    }
-
     pub(crate) fn get_trait_path(&self) -> Option<Path> {
         if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
             Some(trait_.clone())
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 977b4bb45b6..d5e0e83696f 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -1,4 +1,4 @@
-use crate::clean::auto_trait::AutoTraitFinder;
+use crate::clean::auto_trait::synthesize_auto_trait_impls;
 use crate::clean::blanket_impl::BlanketImplFinder;
 use crate::clean::render_macro_matchers::render_macro_matcher;
 use crate::clean::{
@@ -251,15 +251,6 @@ pub(super) fn clean_middle_path<'tcx>(
     }
 }
 
-/// Remove the generic arguments from a path.
-pub(crate) fn strip_path_generics(mut path: Path) -> Path {
-    for ps in path.segments.iter_mut() {
-        ps.args = GenericArgs::AngleBracketed { args: Default::default(), bindings: ThinVec::new() }
-    }
-
-    path
-}
-
 pub(crate) fn qpath_to_string(p: &hir::QPath<'_>) -> String {
     let segments = match *p {
         hir::QPath::Resolved(_, path) => &path.segments,
@@ -486,6 +477,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
     }
 }
 
+// FIXME(fmease): Update the `get_*` terminology to the `synthesize_` one.
 pub(crate) fn get_auto_trait_and_blanket_impls(
     cx: &mut DocContext<'_>,
     item_def_id: DefId,
@@ -493,8 +485,8 @@ pub(crate) fn get_auto_trait_and_blanket_impls(
     let auto_impls = cx
         .sess()
         .prof
-        .generic_activity("get_auto_trait_impls")
-        .run(|| AutoTraitFinder::new(cx).get_auto_trait_impls(item_def_id));
+        .generic_activity("synthesize_auto_trait_impls")
+        .run(|| synthesize_auto_trait_impls(cx, item_def_id));
     let blanket_impls = cx
         .sess()
         .prof
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index f1887684797..4e46f847fd7 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -184,40 +184,15 @@ pub(crate) enum RenderTypeId {
 
 impl RenderTypeId {
     pub fn write_to_string(&self, string: &mut String) {
-        // (sign, value)
-        let (sign, id): (bool, u32) = match &self {
+        let id: i32 = match &self {
             // 0 is a sentinel, everything else is one-indexed
             // concrete type
-            RenderTypeId::Index(idx) if *idx >= 0 => (false, (idx + 1isize).try_into().unwrap()),
+            RenderTypeId::Index(idx) if *idx >= 0 => (idx + 1isize).try_into().unwrap(),
             // generic type parameter
-            RenderTypeId::Index(idx) => (true, (-*idx).try_into().unwrap()),
+            RenderTypeId::Index(idx) => (*idx).try_into().unwrap(),
             _ => panic!("must convert render types to indexes before serializing"),
         };
-        // zig-zag encoding
-        let value: u32 = (id << 1) | (if sign { 1 } else { 0 });
-        // Self-terminating hex use capital letters for everything but the
-        // least significant digit, which is lowercase. For example, decimal 17
-        // would be `` Aa `` if zig-zag encoding weren't used.
-        //
-        // Zig-zag encoding, however, stores the sign bit as the last bit.
-        // This means, in the last hexit, 1 is actually `c`, -1 is `b`
-        // (`a` is the imaginary -0), and, because all the bits are shifted
-        // by one, `` A` `` is actually 8 and `` Aa `` is -8.
-        //
-        // https://rust-lang.github.io/rustc-dev-guide/rustdoc-internals/search.html
-        // describes the encoding in more detail.
-        let mut shift: u32 = 28;
-        let mut mask: u32 = 0xF0_00_00_00;
-        while shift < 32 {
-            let hexit = (value & mask) >> shift;
-            if hexit != 0 || shift == 0 {
-                let hex =
-                    char::try_from(if shift == 0 { '`' } else { '@' } as u32 + hexit).unwrap();
-                string.push(hex);
-            }
-            shift = shift.wrapping_sub(4);
-            mask = mask >> 4;
-        }
+        search_index::encode::write_vlqhex_to_string(id, string);
     }
 }
 
@@ -2506,7 +2481,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
         // Look for the example file in the source map if it exists, otherwise return a dummy span
         let file_span = (|| {
             let source_map = tcx.sess.source_map();
-            let crate_src = tcx.sess.local_crate_source_file()?;
+            let crate_src = tcx.sess.local_crate_source_file()?.into_local_path()?;
             let abs_crate_src = crate_src.canonicalize().ok()?;
             let crate_root = abs_crate_src.parent()?.parent()?;
             let rel_path = path.strip_prefix(crate_root).ok()?;
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index be2786c99ec..51f90e45500 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -1,3 +1,5 @@
+pub(crate) mod encode;
+
 use std::collections::hash_map::Entry;
 use std::collections::{BTreeMap, VecDeque};
 
@@ -17,12 +19,46 @@ use crate::html::format::join_with_double_colon;
 use crate::html::markdown::short_markdown_summary;
 use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId};
 
+use encode::{bitmap_to_string, write_vlqhex_to_string};
+
+/// The serialized search description sharded version
+///
+/// The `index` is a JSON-encoded list of names and other information.
+///
+/// The desc has newlined descriptions, split up by size into 128KiB shards.
+/// For example, `(4, "foo\nbar\nbaz\nquux")`.
+///
+/// There is no single, optimal size for these shards, because it depends on
+/// configuration values that we can't predict or control, such as the version
+/// of HTTP used (HTTP/1.1 would work better with larger files, while HTTP/2
+/// and 3 are more agnostic), transport compression (gzip, zstd, etc), whether
+/// the search query is going to produce a large number of results or a small
+/// number, the bandwidth delay product of the network...
+///
+/// Gzipping some standard library descriptions to guess what transport
+/// compression will do, the compressed file sizes can be as small as 4.9KiB
+/// or as large as 18KiB (ignoring the final 1.9KiB shard of leftovers).
+/// A "reasonable" range for files is for them to be bigger than 1KiB,
+/// since that's about the amount of data that can be transferred in a
+/// single TCP packet, and 64KiB, the maximum amount of data that
+/// TCP can transfer in a single round trip without extensions.
+///
+/// [1]: https://en.wikipedia.org/wiki/Maximum_transmission_unit#MTUs_for_common_media
+/// [2]: https://en.wikipedia.org/wiki/Sliding_window_protocol#Basic_concept
+/// [3]: https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/description-tcp-features
+pub(crate) struct SerializedSearchIndex {
+    pub(crate) index: String,
+    pub(crate) desc: Vec<(usize, String)>,
+}
+
+const DESC_INDEX_SHARD_LEN: usize = 128 * 1024;
+
 /// Builds the search index from the collected metadata
 pub(crate) fn build_index<'tcx>(
     krate: &clean::Crate,
     cache: &mut Cache,
     tcx: TyCtxt<'tcx>,
-) -> String {
+) -> SerializedSearchIndex {
     let mut itemid_to_pathid = FxHashMap::default();
     let mut primitives = FxHashMap::default();
     let mut associated_types = FxHashMap::default();
@@ -319,7 +355,6 @@ pub(crate) fn build_index<'tcx>(
         .collect::<Vec<_>>();
 
     struct CrateData<'a> {
-        doc: String,
         items: Vec<&'a IndexItem>,
         paths: Vec<(ItemType, Vec<Symbol>)>,
         // The String is alias name and the vec is the list of the elements with this alias.
@@ -328,6 +363,11 @@ pub(crate) fn build_index<'tcx>(
         aliases: &'a BTreeMap<String, Vec<usize>>,
         // Used when a type has more than one impl with an associated item with the same name.
         associated_item_disambiguators: &'a Vec<(usize, String)>,
+        // A list of shard lengths encoded as vlqhex. See the comment in write_vlqhex_to_string
+        // for information on the format.
+        desc_index: String,
+        // A list of items with no description. This is eventually turned into a bitmap.
+        empty_desc: Vec<u32>,
     }
 
     struct Paths {
@@ -409,7 +449,6 @@ pub(crate) fn build_index<'tcx>(
             let mut names = Vec::with_capacity(self.items.len());
             let mut types = String::with_capacity(self.items.len());
             let mut full_paths = Vec::with_capacity(self.items.len());
-            let mut descriptions = Vec::with_capacity(self.items.len());
             let mut parents = Vec::with_capacity(self.items.len());
             let mut functions = String::with_capacity(self.items.len());
             let mut deprecated = Vec::with_capacity(self.items.len());
@@ -432,7 +471,6 @@ pub(crate) fn build_index<'tcx>(
                 parents.push(item.parent_idx.map(|x| x + 1).unwrap_or(0));
 
                 names.push(item.name.as_str());
-                descriptions.push(&item.desc);
 
                 if !item.path.is_empty() {
                     full_paths.push((index, &item.path));
@@ -444,7 +482,8 @@ pub(crate) fn build_index<'tcx>(
                 }
 
                 if item.deprecation.is_some() {
-                    deprecated.push(index);
+                    // bitmasks always use 1-indexing for items, with 0 as the crate itself
+                    deprecated.push(u32::try_from(index + 1).unwrap());
                 }
             }
 
@@ -455,17 +494,16 @@ pub(crate) fn build_index<'tcx>(
             let has_aliases = !self.aliases.is_empty();
             let mut crate_data =
                 serializer.serialize_struct("CrateData", if has_aliases { 9 } else { 8 })?;
-            crate_data.serialize_field("doc", &self.doc)?;
             crate_data.serialize_field("t", &types)?;
             crate_data.serialize_field("n", &names)?;
-            // Serialize as an array of item indices and full paths
             crate_data.serialize_field("q", &full_paths)?;
-            crate_data.serialize_field("d", &descriptions)?;
             crate_data.serialize_field("i", &parents)?;
             crate_data.serialize_field("f", &functions)?;
-            crate_data.serialize_field("c", &deprecated)?;
+            crate_data.serialize_field("D", &self.desc_index)?;
             crate_data.serialize_field("p", &paths)?;
             crate_data.serialize_field("b", &self.associated_item_disambiguators)?;
+            crate_data.serialize_field("c", &bitmap_to_string(&deprecated))?;
+            crate_data.serialize_field("e", &bitmap_to_string(&self.empty_desc))?;
             if has_aliases {
                 crate_data.serialize_field("a", &self.aliases)?;
             }
@@ -473,16 +511,58 @@ pub(crate) fn build_index<'tcx>(
         }
     }
 
-    // Collect the index into a string
-    format!(
+    let (empty_desc, desc) = {
+        let mut empty_desc = Vec::new();
+        let mut result = Vec::new();
+        let mut set = String::new();
+        let mut len: usize = 0;
+        let mut item_index: u32 = 0;
+        for desc in std::iter::once(&crate_doc).chain(crate_items.iter().map(|item| &item.desc)) {
+            if desc == "" {
+                empty_desc.push(item_index);
+                item_index += 1;
+                continue;
+            }
+            if set.len() >= DESC_INDEX_SHARD_LEN {
+                result.push((len, std::mem::replace(&mut set, String::new())));
+                len = 0;
+            } else if len != 0 {
+                set.push('\n');
+            }
+            set.push_str(&desc);
+            len += 1;
+            item_index += 1;
+        }
+        result.push((len, std::mem::replace(&mut set, String::new())));
+        (empty_desc, result)
+    };
+
+    let desc_index = {
+        let mut desc_index = String::with_capacity(desc.len() * 4);
+        for &(len, _) in desc.iter() {
+            write_vlqhex_to_string(len.try_into().unwrap(), &mut desc_index);
+        }
+        desc_index
+    };
+
+    assert_eq!(
+        crate_items.len() + 1,
+        desc.iter().map(|(len, _)| *len).sum::<usize>() + empty_desc.len()
+    );
+
+    // The index, which is actually used to search, is JSON
+    // It uses `JSON.parse(..)` to actually load, since JSON
+    // parses faster than the full JavaScript syntax.
+    let index = format!(
         r#"["{}",{}]"#,
         krate.name(tcx),
         serde_json::to_string(&CrateData {
-            doc: crate_doc,
             items: crate_items,
             paths: crate_paths,
             aliases: &aliases,
             associated_item_disambiguators: &associated_item_disambiguators,
+            desc_index,
+            empty_desc,
         })
         .expect("failed serde conversion")
         // All these `replace` calls are because we have to go through JS string for JSON content.
@@ -490,7 +570,8 @@ pub(crate) fn build_index<'tcx>(
         .replace('\'', r"\'")
         // We need to escape double quotes for the JSON.
         .replace("\\\"", "\\\\\"")
-    )
+    );
+    SerializedSearchIndex { index, desc }
 }
 
 pub(crate) fn get_function_type_for_search<'tcx>(
diff --git a/src/librustdoc/html/render/search_index/encode.rs b/src/librustdoc/html/render/search_index/encode.rs
new file mode 100644
index 00000000000..54407c614c4
--- /dev/null
+++ b/src/librustdoc/html/render/search_index/encode.rs
@@ -0,0 +1,243 @@
+use base64::prelude::*;
+
+pub(crate) fn write_vlqhex_to_string(n: i32, string: &mut String) {
+    let (sign, magnitude): (bool, u32) =
+        if n >= 0 { (false, n.try_into().unwrap()) } else { (true, (-n).try_into().unwrap()) };
+    // zig-zag encoding
+    let value: u32 = (magnitude << 1) | (if sign { 1 } else { 0 });
+    // Self-terminating hex use capital letters for everything but the
+    // least significant digit, which is lowercase. For example, decimal 17
+    // would be `` Aa `` if zig-zag encoding weren't used.
+    //
+    // Zig-zag encoding, however, stores the sign bit as the last bit.
+    // This means, in the last hexit, 1 is actually `c`, -1 is `b`
+    // (`a` is the imaginary -0), and, because all the bits are shifted
+    // by one, `` A` `` is actually 8 and `` Aa `` is -8.
+    //
+    // https://rust-lang.github.io/rustc-dev-guide/rustdoc-internals/search.html
+    // describes the encoding in more detail.
+    let mut shift: u32 = 28;
+    let mut mask: u32 = 0xF0_00_00_00;
+    // first skip leading zeroes
+    while shift < 32 {
+        let hexit = (value & mask) >> shift;
+        if hexit != 0 || shift == 0 {
+            break;
+        }
+        shift = shift.wrapping_sub(4);
+        mask = mask >> 4;
+    }
+    // now write the rest
+    while shift < 32 {
+        let hexit = (value & mask) >> shift;
+        let hex = char::try_from(if shift == 0 { '`' } else { '@' } as u32 + hexit).unwrap();
+        string.push(hex);
+        shift = shift.wrapping_sub(4);
+        mask = mask >> 4;
+    }
+}
+
+// Used during bitmap encoding
+enum Container {
+    /// number of ones, bits
+    Bits(Box<[u64; 1024]>),
+    /// list of entries
+    Array(Vec<u16>),
+    /// list of (start, len-1)
+    Run(Vec<(u16, u16)>),
+}
+impl Container {
+    fn popcount(&self) -> u32 {
+        match self {
+            Container::Bits(bits) => bits.iter().copied().map(|x| x.count_ones()).sum(),
+            Container::Array(array) => {
+                array.len().try_into().expect("array can't be bigger than 2**32")
+            }
+            Container::Run(runs) => {
+                runs.iter().copied().map(|(_, lenm1)| u32::from(lenm1) + 1).sum()
+            }
+        }
+    }
+    fn push(&mut self, value: u16) {
+        match self {
+            Container::Bits(bits) => bits[value as usize >> 6] |= 1 << (value & 0x3F),
+            Container::Array(array) => {
+                array.push(value);
+                if array.len() >= 4096 {
+                    let array = std::mem::replace(array, Vec::new());
+                    *self = Container::Bits(Box::new([0; 1024]));
+                    for value in array {
+                        self.push(value);
+                    }
+                }
+            }
+            Container::Run(runs) => {
+                if let Some(r) = runs.last_mut()
+                    && r.0 + r.1 + 1 == value
+                {
+                    r.1 += 1;
+                } else {
+                    runs.push((value, 0));
+                }
+            }
+        }
+    }
+    fn try_make_run(&mut self) -> bool {
+        match self {
+            Container::Bits(bits) => {
+                let mut r: u64 = 0;
+                for (i, chunk) in bits.iter().copied().enumerate() {
+                    let next_chunk =
+                        i.checked_add(1).and_then(|i| bits.get(i)).copied().unwrap_or(0);
+                    r += !chunk & u64::from((chunk << 1).count_ones());
+                    r += !next_chunk & u64::from((chunk >> 63).count_ones());
+                }
+                if (2 + 4 * r) >= 8192 {
+                    return false;
+                }
+                let bits = std::mem::replace(bits, Box::new([0; 1024]));
+                *self = Container::Run(Vec::new());
+                for (i, bits) in bits.iter().copied().enumerate() {
+                    if bits == 0 {
+                        continue;
+                    }
+                    for j in 0..64 {
+                        let value = (u16::try_from(i).unwrap() << 6) | j;
+                        if bits & (1 << j) != 0 {
+                            self.push(value);
+                        }
+                    }
+                }
+                true
+            }
+            Container::Array(array) if array.len() <= 5 => false,
+            Container::Array(array) => {
+                let mut r = 0;
+                let mut prev = None;
+                for value in array.iter().copied() {
+                    if value.checked_sub(1) != prev {
+                        r += 1;
+                    }
+                    prev = Some(value);
+                }
+                if 2 + 4 * r >= 2 * array.len() + 2 {
+                    return false;
+                }
+                let array = std::mem::replace(array, Vec::new());
+                *self = Container::Run(Vec::new());
+                for value in array {
+                    self.push(value);
+                }
+                true
+            }
+            Container::Run(_) => true,
+        }
+    }
+}
+
+// checked against roaring-rs in
+// https://gitlab.com/notriddle/roaring-test
+pub(crate) fn write_bitmap_to_bytes(
+    domain: &[u32],
+    mut out: impl std::io::Write,
+) -> std::io::Result<()> {
+    // https://arxiv.org/pdf/1603.06549.pdf
+    let mut keys = Vec::<u16>::new();
+    let mut containers = Vec::<Container>::new();
+    let mut key: u16;
+    let mut domain_iter = domain.into_iter().copied().peekable();
+    let mut has_run = false;
+    while let Some(entry) = domain_iter.next() {
+        key = (entry >> 16).try_into().expect("shifted off the top 16 bits, so it should fit");
+        let value: u16 = (entry & 0x00_00_FF_FF).try_into().expect("AND 16 bits, so it should fit");
+        let mut container = Container::Array(vec![value]);
+        while let Some(entry) = domain_iter.peek().copied() {
+            let entry_key: u16 =
+                (entry >> 16).try_into().expect("shifted off the top 16 bits, so it should fit");
+            if entry_key != key {
+                break;
+            }
+            domain_iter.next().expect("peeking just succeeded");
+            container
+                .push((entry & 0x00_00_FF_FF).try_into().expect("AND 16 bits, so it should fit"));
+        }
+        keys.push(key);
+        has_run = container.try_make_run() || has_run;
+        containers.push(container);
+    }
+    // https://github.com/RoaringBitmap/RoaringFormatSpec
+    use byteorder::{WriteBytesExt, LE};
+    const SERIAL_COOKIE_NO_RUNCONTAINER: u32 = 12346;
+    const SERIAL_COOKIE: u32 = 12347;
+    const NO_OFFSET_THRESHOLD: u32 = 4;
+    let size: u32 = containers.len().try_into().unwrap();
+    let start_offset = if has_run {
+        out.write_u32::<LE>(SERIAL_COOKIE | ((size - 1) << 16))?;
+        for set in containers.chunks(8) {
+            let mut b = 0;
+            for (i, container) in set.iter().enumerate() {
+                if matches!(container, &Container::Run(..)) {
+                    b |= 1 << i;
+                }
+            }
+            out.write_u8(b)?;
+        }
+        if size < NO_OFFSET_THRESHOLD {
+            4 + 4 * size + ((size + 7) / 8)
+        } else {
+            4 + 8 * size + ((size + 7) / 8)
+        }
+    } else {
+        out.write_u32::<LE>(SERIAL_COOKIE_NO_RUNCONTAINER)?;
+        out.write_u32::<LE>(containers.len().try_into().unwrap())?;
+        4 + 4 + 4 * size + 4 * size
+    };
+    for (&key, container) in keys.iter().zip(&containers) {
+        // descriptive header
+        let key: u32 = key.into();
+        let count: u32 = container.popcount() - 1;
+        out.write_u32::<LE>((count << 16) | key)?;
+    }
+    if !has_run || size >= NO_OFFSET_THRESHOLD {
+        // offset header
+        let mut starting_offset = start_offset;
+        for container in &containers {
+            out.write_u32::<LE>(starting_offset)?;
+            starting_offset += match container {
+                Container::Bits(_) => 8192u32,
+                Container::Array(array) => u32::try_from(array.len()).unwrap() * 2,
+                Container::Run(runs) => 2 + u32::try_from(runs.len()).unwrap() * 4,
+            };
+        }
+    }
+    for container in &containers {
+        match container {
+            Container::Bits(bits) => {
+                for chunk in bits.iter() {
+                    out.write_u64::<LE>(*chunk)?;
+                }
+            }
+            Container::Array(array) => {
+                for value in array.iter() {
+                    out.write_u16::<LE>(*value)?;
+                }
+            }
+            Container::Run(runs) => {
+                out.write_u16::<LE>((runs.len()).try_into().unwrap())?;
+                for (start, lenm1) in runs.iter().copied() {
+                    out.write_u16::<LE>(start)?;
+                    out.write_u16::<LE>(lenm1)?;
+                }
+            }
+        }
+    }
+    Ok(())
+}
+
+pub(crate) fn bitmap_to_string(domain: &[u32]) -> String {
+    let mut buf = Vec::new();
+    let mut strbuf = String::new();
+    write_bitmap_to_bytes(&domain, &mut buf).unwrap();
+    BASE64_STANDARD.encode_string(&buf, &mut strbuf);
+    strbuf
+}
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index fbd45b2b48e..c806bf1cc66 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -24,6 +24,7 @@ use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
 use crate::html::format::Buffer;
+use crate::html::render::search_index::SerializedSearchIndex;
 use crate::html::render::{AssocItemLink, ImplRenderingParameters};
 use crate::html::{layout, static_files};
 use crate::visit::DocVisitor;
@@ -46,7 +47,7 @@ use crate::{try_err, try_none};
 pub(super) fn write_shared(
     cx: &mut Context<'_>,
     krate: &Crate,
-    search_index: String,
+    search_index: SerializedSearchIndex,
     options: &RenderOptions,
 ) -> Result<(), Error> {
     // Write out the shared files. Note that these are shared among all rustdoc
@@ -312,7 +313,7 @@ pub(super) fn write_shared(
     let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix));
     let (mut all_indexes, mut krates) =
         try_err!(collect_json(&dst, krate.name(cx.tcx()).as_str()), &dst);
-    all_indexes.push(search_index);
+    all_indexes.push(search_index.index);
     krates.push(krate.name(cx.tcx()).to_string());
     krates.sort();
 
@@ -335,6 +336,32 @@ else if (window.initSearch) window.initSearch(searchIndex);
         Ok(v.into_bytes())
     })?;
 
+    let search_desc_dir = cx.dst.join(format!("search.desc/{krate}", krate = krate.name(cx.tcx())));
+    if Path::new(&search_desc_dir).exists() {
+        try_err!(std::fs::remove_dir_all(&search_desc_dir), &search_desc_dir);
+    }
+    try_err!(std::fs::create_dir_all(&search_desc_dir), &search_desc_dir);
+    let kratename = krate.name(cx.tcx()).to_string();
+    for (i, (_, data)) in search_index.desc.into_iter().enumerate() {
+        let output_filename = static_files::suffix_path(
+            &format!("{kratename}-desc-{i}-.js"),
+            &cx.shared.resource_suffix,
+        );
+        let path = search_desc_dir.join(output_filename);
+        try_err!(
+            std::fs::write(
+                &path,
+                &format!(
+                    r##"searchState.loadedDescShard({kratename}, {i}, {data})"##,
+                    kratename = serde_json::to_string(&kratename).unwrap(),
+                    data = serde_json::to_string(&data).unwrap(),
+                )
+                .into_bytes()
+            ),
+            &path
+        );
+    }
+
     write_invocation_specific("crates.js", &|| {
         let krates = krates.iter().map(|k| format!("\"{k}\"")).join(",");
         Ok(format!("window.ALL_CRATES = [{krates}];").into_bytes())
diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js
index 1a34530c2d1..a1e9cc6dfa1 100644
--- a/src/librustdoc/html/static/.eslintrc.js
+++ b/src/librustdoc/html/static/.eslintrc.js
@@ -5,7 +5,7 @@ module.exports = {
     },
     "extends": "eslint:recommended",
     "parserOptions": {
-        "ecmaVersion": 2015,
+        "ecmaVersion": 8,
         "sourceType": "module"
     },
     "rules": {
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index b9a769a7c6d..940b62be0c9 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -329,6 +329,30 @@ function preLoadCss(cssUrl) {
             search.innerHTML = "<h3 class=\"search-loading\">" + searchState.loadingText + "</h3>";
             searchState.showResults(search);
         },
+        descShards: new Map(),
+        loadDesc: async function({descShard, descIndex}) {
+            if (descShard.promise === null) {
+                descShard.promise = new Promise((resolve, reject) => {
+                    // The `resolve` callback is stored in the `descShard`
+                    // object, which is itself stored in `this.descShards` map.
+                    // It is called in `loadedDescShard` by the
+                    // search.desc script.
+                    descShard.resolve = resolve;
+                    const ds = descShard;
+                    const fname = `${ds.crate}-desc-${ds.shard}-`;
+                    const url = resourcePath(
+                        `search.desc/${descShard.crate}/${fname}`,
+                        ".js",
+                    );
+                    loadScript(url, reject);
+                });
+            }
+            const list = await descShard.promise;
+            return list[descIndex];
+        },
+        loadedDescShard: function(crate, shard, data) {
+            this.descShards.get(crate)[shard].resolve(data.split("\n"));
+        },
     };
 
     const toggleAllDocsId = "toggle-all-docs";
@@ -381,7 +405,7 @@ function preLoadCss(cssUrl) {
                                     window.location.replace("#" + item.id);
                                 }, 0);
                             }
-                        }
+                        },
                     );
                 }
             }
@@ -585,7 +609,7 @@ function preLoadCss(cssUrl) {
         const script = document
             .querySelector("script[data-ignore-extern-crates]");
         const ignoreExternCrates = new Set(
-            (script ? script.getAttribute("data-ignore-extern-crates") : "").split(",")
+            (script ? script.getAttribute("data-ignore-extern-crates") : "").split(","),
         );
         for (const lib of libs) {
             if (lib === window.currentCrate || ignoreExternCrates.has(lib)) {
@@ -1098,7 +1122,7 @@ function preLoadCss(cssUrl) {
         } else {
             wrapper.style.setProperty(
                 "--popover-arrow-offset",
-                (wrapperPos.right - pos.right + 4) + "px"
+                (wrapperPos.right - pos.right + 4) + "px",
             );
         }
         wrapper.style.visibility = "";
@@ -1680,7 +1704,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
                 pendingSidebarResizingFrame = false;
                 document.documentElement.style.setProperty(
                     "--resizing-sidebar-width",
-                    desiredSidebarSize + "px"
+                    desiredSidebarSize + "px",
                 );
             }, 100);
         }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 875ebe2fc90..3daf1ad22de 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -206,14 +206,14 @@ const editDistanceState = {
                     // insertion
                     this.current[j - 1] + 1,
                     // substitution
-                    this.prev[j - 1] + substitutionCost
+                    this.prev[j - 1] + substitutionCost,
                 );
 
                 if ((i > 1) && (j > 1) && (a[aIdx] === b[bIdx - 1]) && (a[aIdx - 1] === b[bIdx])) {
                     // transposition
                     this.current[j] = Math.min(
                         this.current[j],
-                        this.prevPrev[j - 2] + 1
+                        this.prevPrev[j - 2] + 1,
                     );
                 }
             }
@@ -243,6 +243,14 @@ function initSearch(rawSearchIndex) {
      */
     let searchIndex;
     /**
+     * @type {Map<String, RoaringBitmap>}
+     */
+    let searchIndexDeprecated;
+    /**
+     * @type {Map<String, RoaringBitmap>}
+     */
+    let searchIndexEmptyDesc;
+    /**
      *  @type {Uint32Array}
      */
     let functionTypeFingerprint;
@@ -426,7 +434,7 @@ function initSearch(rawSearchIndex) {
         return c === "," || c === "=";
     }
 
-/**
+    /**
      * Returns `true` if the given `c` character is a path separator. For example
      * `:` in `a::b` or a whitespace in `a b`.
      *
@@ -856,8 +864,8 @@ function initSearch(rawSearchIndex) {
                         parserState,
                         parserState.userQuery.slice(start, end),
                         generics,
-                        isInGenerics
-                    )
+                        isInGenerics,
+                    ),
                 );
             }
         }
@@ -1295,7 +1303,7 @@ function initSearch(rawSearchIndex) {
      *
      * @return {ResultsTable}
      */
-    function execQuery(parsedQuery, filterCrates, currentCrate) {
+    async function execQuery(parsedQuery, filterCrates, currentCrate) {
         const results_others = new Map(), results_in_args = new Map(),
             results_returned = new Map();
 
@@ -1342,9 +1350,9 @@ function initSearch(rawSearchIndex) {
          * @param {Results} results
          * @param {boolean} isType
          * @param {string} preferredCrate
-         * @returns {[ResultObject]}
+         * @returns {Promise<[ResultObject]>}
          */
-        function sortResults(results, isType, preferredCrate) {
+        async function sortResults(results, isType, preferredCrate) {
             const userQuery = parsedQuery.userQuery;
             const result_list = [];
             for (const result of results.values()) {
@@ -1394,8 +1402,8 @@ function initSearch(rawSearchIndex) {
                 }
 
                 // sort deprecated items later
-                a = aaa.item.deprecated;
-                b = bbb.item.deprecated;
+                a = searchIndexDeprecated.get(aaa.item.crate).contains(aaa.item.bitIndex);
+                b = searchIndexDeprecated.get(bbb.item.crate).contains(bbb.item.bitIndex);
                 if (a !== b) {
                     return a - b;
                 }
@@ -1422,8 +1430,8 @@ function initSearch(rawSearchIndex) {
                 }
 
                 // sort by description (no description goes later)
-                a = (aaa.item.desc === "");
-                b = (bbb.item.desc === "");
+                a = searchIndexEmptyDesc.get(aaa.item.crate).contains(aaa.item.bitIndex);
+                b = searchIndexEmptyDesc.get(bbb.item.crate).contains(bbb.item.bitIndex);
                 if (a !== b) {
                     return a - b;
                 }
@@ -1446,7 +1454,16 @@ function initSearch(rawSearchIndex) {
                 return 0;
             });
 
-            return transformResults(result_list);
+            const transformed = transformResults(result_list);
+            const descs = await Promise.all(transformed.map(result => {
+                return searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex) ?
+                    "" :
+                    searchState.loadDesc(result);
+            }));
+            for (const [i, result] of transformed.entries()) {
+                result.desc = descs[i];
+            }
+            return transformed;
         }
 
         /**
@@ -1477,7 +1494,7 @@ function initSearch(rawSearchIndex) {
             whereClause,
             mgensIn,
             solutionCb,
-            unboxingDepth
+            unboxingDepth,
         ) {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
@@ -1524,7 +1541,7 @@ function initSearch(rawSearchIndex) {
                         queryElem,
                         whereClause,
                         mgens,
-                        unboxingDepth + 1
+                        unboxingDepth + 1,
                     )) {
                         continue;
                     }
@@ -1541,7 +1558,7 @@ function initSearch(rawSearchIndex) {
                             whereClause,
                             mgensScratch,
                             solutionCb,
-                            unboxingDepth + 1
+                            unboxingDepth + 1,
                         )) {
                             return true;
                         }
@@ -1551,7 +1568,7 @@ function initSearch(rawSearchIndex) {
                         whereClause,
                         mgens ? new Map(mgens) : null,
                         solutionCb,
-                        unboxingDepth + 1
+                        unboxingDepth + 1,
                     )) {
                         return true;
                     }
@@ -1625,7 +1642,7 @@ function initSearch(rawSearchIndex) {
                             queryElem,
                             whereClause,
                             mgensScratch,
-                            unboxingDepth
+                            unboxingDepth,
                         );
                         if (!solution) {
                             return false;
@@ -1638,7 +1655,7 @@ function initSearch(rawSearchIndex) {
                                 whereClause,
                                 simplifiedMgens,
                                 solutionCb,
-                                unboxingDepth
+                                unboxingDepth,
                             );
                             if (passesUnification) {
                                 return true;
@@ -1646,7 +1663,7 @@ function initSearch(rawSearchIndex) {
                         }
                         return false;
                     },
-                    unboxingDepth
+                    unboxingDepth,
                 );
                 if (passesUnification) {
                     return true;
@@ -1663,7 +1680,7 @@ function initSearch(rawSearchIndex) {
                     queryElem,
                     whereClause,
                     mgens,
-                    unboxingDepth + 1
+                    unboxingDepth + 1,
                 )) {
                     continue;
                 }
@@ -1689,7 +1706,7 @@ function initSearch(rawSearchIndex) {
                     whereClause,
                     mgensScratch,
                     solutionCb,
-                    unboxingDepth + 1
+                    unboxingDepth + 1,
                 );
                 if (passesUnification) {
                     return true;
@@ -1820,7 +1837,7 @@ function initSearch(rawSearchIndex) {
             queryElem,
             whereClause,
             mgensIn,
-            unboxingDepth
+            unboxingDepth,
         ) {
             if (fnType.bindings.size < queryElem.bindings.size) {
                 return false;
@@ -1849,7 +1866,7 @@ function initSearch(rawSearchIndex) {
                                 // possible solutions
                                 return false;
                             },
-                            unboxingDepth
+                            unboxingDepth,
                         );
                         return newSolutions;
                     });
@@ -1887,7 +1904,7 @@ function initSearch(rawSearchIndex) {
             queryElem,
             whereClause,
             mgens,
-            unboxingDepth
+            unboxingDepth,
         ) {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
@@ -1914,7 +1931,7 @@ function initSearch(rawSearchIndex) {
                     queryElem,
                     whereClause,
                     mgensTmp,
-                    unboxingDepth
+                    unboxingDepth,
                 );
             } else if (fnType.generics.length > 0 || fnType.bindings.size > 0) {
                 const simplifiedGenerics = [
@@ -1926,7 +1943,7 @@ function initSearch(rawSearchIndex) {
                     queryElem,
                     whereClause,
                     mgens,
-                    unboxingDepth
+                    unboxingDepth,
                 );
             }
             return false;
@@ -1975,7 +1992,7 @@ function initSearch(rawSearchIndex) {
                         elem,
                         whereClause,
                         mgens,
-                        unboxingDepth + 1
+                        unboxingDepth + 1,
                     );
                 }
                 if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
@@ -1989,7 +2006,7 @@ function initSearch(rawSearchIndex) {
                         elem,
                         whereClause,
                         mgens,
-                        unboxingDepth
+                        unboxingDepth,
                     );
                 }
             }
@@ -2007,7 +2024,7 @@ function initSearch(rawSearchIndex) {
                 return 0;
             }
             const maxPathEditDistance = Math.floor(
-                contains.reduce((acc, next) => acc + next.length, 0) / 3
+                contains.reduce((acc, next) => acc + next.length, 0) / 3,
             );
             let ret_dist = maxPathEditDistance + 1;
             const path = ty.path.split("::");
@@ -2066,12 +2083,13 @@ function initSearch(rawSearchIndex) {
                 crate: item.crate,
                 name: item.name,
                 path: item.path,
-                desc: item.desc,
+                descShard: item.descShard,
+                descIndex: item.descIndex,
                 ty: item.ty,
                 parent: item.parent,
                 type: item.type,
                 is_alias: true,
-                deprecated: item.deprecated,
+                bitIndex: item.bitIndex,
                 implDisambiguator: item.implDisambiguator,
             };
         }
@@ -2192,7 +2210,7 @@ function initSearch(rawSearchIndex) {
             results_others,
             results_in_args,
             results_returned,
-            maxEditDistance
+            maxEditDistance,
         ) {
             if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
                 return;
@@ -2204,7 +2222,7 @@ function initSearch(rawSearchIndex) {
             // atoms in the function not present in the query
             const tfpDist = compareTypeFingerprints(
                 fullId,
-                parsedQuery.typeFingerprint
+                parsedQuery.typeFingerprint,
             );
             if (tfpDist !== null) {
                 const in_args = row.type && row.type.inputs
@@ -2276,7 +2294,7 @@ function initSearch(rawSearchIndex) {
 
             const tfpDist = compareTypeFingerprints(
                 row.id,
-                parsedQuery.typeFingerprint
+                parsedQuery.typeFingerprint,
             );
             if (tfpDist === null) {
                 return;
@@ -2298,10 +2316,10 @@ function initSearch(rawSearchIndex) {
                         row.type.where_clause,
                         mgens,
                         null,
-                        0 // unboxing depth
+                        0, // unboxing depth
                     );
                 },
-                0 // unboxing depth
+                0, // unboxing depth
             )) {
                 return;
             }
@@ -2419,7 +2437,7 @@ function initSearch(rawSearchIndex) {
                         }
 
                         return [typeNameIdMap.get(name).id, constraints];
-                    })
+                    }),
                 );
             }
 
@@ -2446,7 +2464,7 @@ function initSearch(rawSearchIndex) {
                             results_others,
                             results_in_args,
                             results_returned,
-                            maxEditDistance
+                            maxEditDistance,
                         );
                     }
                 }
@@ -2477,10 +2495,15 @@ function initSearch(rawSearchIndex) {
             innerRunQuery();
         }
 
-        const ret = createQueryResults(
+        const [sorted_in_args, sorted_returned, sorted_others] = await Promise.all([
             sortResults(results_in_args, true, currentCrate),
             sortResults(results_returned, true, currentCrate),
             sortResults(results_others, false, currentCrate),
+        ]);
+        const ret = createQueryResults(
+            sorted_in_args,
+            sorted_returned,
+            sorted_others,
             parsedQuery);
         handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates, currentCrate);
         if (parsedQuery.error !== null && ret.others.length !== 0) {
@@ -2581,14 +2604,14 @@ function initSearch(rawSearchIndex) {
      * @param {ParsedQuery} query
      * @param {boolean}     display - True if this is the active tab
      */
-    function addTab(array, query, display) {
+    async function addTab(array, query, display) {
         const extraClass = display ? " active" : "";
 
         const output = document.createElement("div");
         if (array.length > 0) {
             output.className = "search-results " + extraClass;
 
-            array.forEach(item => {
+            for (const item of array) {
                 const name = item.name;
                 const type = itemTypes[item.ty];
                 const longType = longItemTypes[item.ty];
@@ -2624,7 +2647,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
 
                 link.appendChild(description);
                 output.appendChild(link);
-            });
+            }
         } else if (query.error === null) {
             output.className = "search-failed" + extraClass;
             output.innerHTML = "No results :(<br/>" +
@@ -2666,7 +2689,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
      * @param {boolean} go_to_first
      * @param {string} filterCrates
      */
-    function showResults(results, go_to_first, filterCrates) {
+    async function showResults(results, go_to_first, filterCrates) {
         const search = searchState.outputElement();
         if (go_to_first || (results.others.length === 1
             && getSettingValue("go-to-only-result") === "true")
@@ -2699,9 +2722,11 @@ ${item.displayPath}<span class="${type}">${name}</span>\
 
         currentResults = results.query.userQuery;
 
-        const ret_others = addTab(results.others, results.query, true);
-        const ret_in_args = addTab(results.in_args, results.query, false);
-        const ret_returned = addTab(results.returned, results.query, false);
+        const [ret_others, ret_in_args, ret_returned] = await Promise.all([
+            addTab(results.others, results.query, true),
+            addTab(results.in_args, results.query, false),
+            addTab(results.returned, results.query, false),
+        ]);
 
         // Navigate to the relevant tab if the current tab is empty, like in case users search
         // for "-> String". If they had selected another tab previously, they have to click on
@@ -2822,7 +2847,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
      * and display the results.
      * @param {boolean} [forced]
      */
-    function search(forced) {
+    async function search(forced) {
         const query = parseQuery(searchState.input.value.trim());
         let filterCrates = getFilterCrates();
 
@@ -2850,8 +2875,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\
         // recent search query is added to the browser history.
         updateSearchHistory(buildUrl(query.original, filterCrates));
 
-        showResults(
-            execQuery(query, filterCrates, window.currentCrate),
+        await showResults(
+            await execQuery(query, filterCrates, window.currentCrate),
             params.go_to_first,
             filterCrates);
     }
@@ -2920,7 +2945,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
             pathIndex = type[PATH_INDEX_DATA];
             generics = buildItemSearchTypeAll(
                 type[GENERICS_DATA],
-                lowercasePaths
+                lowercasePaths,
             );
             if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) {
                 bindings = new Map(type[BINDINGS_DATA].map(binding => {
@@ -3030,101 +3055,49 @@ ${item.displayPath}<span class="${type}">${name}</span>\
      * The raw function search type format is generated using serde in
      * librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string
      *
-     * @param {{
-     *  string: string,
-     *  offset: number,
-     *  backrefQueue: FunctionSearchType[]
-     * }} itemFunctionDecoder
      * @param {Array<{name: string, ty: number}>} lowercasePaths
-     * @param {Map<string, integer>}
      *
      * @return {null|FunctionSearchType}
      */
-    function buildFunctionSearchType(itemFunctionDecoder, lowercasePaths) {
-        const c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
-        itemFunctionDecoder.offset += 1;
-        const [zero, ua, la, ob, cb] = ["0", "@", "`", "{", "}"].map(c => c.charCodeAt(0));
-        // `` ` `` is used as a sentinel because it's fewer bytes than `null`, and decodes to zero
-        // `0` is a backref
-        if (c === la) {
-            return null;
-        }
-        // sixteen characters after "0" are backref
-        if (c >= zero && c < ua) {
-            return itemFunctionDecoder.backrefQueue[c - zero];
-        }
-        if (c !== ob) {
-            throw ["Unexpected ", c, " in function: expected ", "{", "; this is a bug"];
-        }
-        // call after consuming `{`
-        function decodeList() {
-            let c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
-            const ret = [];
-            while (c !== cb) {
-                ret.push(decode());
-                c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
-            }
-            itemFunctionDecoder.offset += 1; // eat cb
-            return ret;
-        }
-        // consumes and returns a list or integer
-        function decode() {
-            let n = 0;
-            let c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
-            if (c === ob) {
-                itemFunctionDecoder.offset += 1;
-                return decodeList();
-            }
-            while (c < la) {
-                n = (n << 4) | (c & 0xF);
-                itemFunctionDecoder.offset += 1;
-                c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
-            }
-            // last character >= la
-            n = (n << 4) | (c & 0xF);
-            const [sign, value] = [n & 1, n >> 1];
-            itemFunctionDecoder.offset += 1;
-            return sign ? -value : value;
-        }
-        const functionSearchType = decodeList();
-        const INPUTS_DATA = 0;
-        const OUTPUT_DATA = 1;
-        let inputs, output;
-        if (typeof functionSearchType[INPUTS_DATA] === "number") {
-            inputs = [buildItemSearchType(functionSearchType[INPUTS_DATA], lowercasePaths)];
-        } else {
-            inputs = buildItemSearchTypeAll(
-                functionSearchType[INPUTS_DATA],
-                lowercasePaths
-            );
-        }
-        if (functionSearchType.length > 1) {
-            if (typeof functionSearchType[OUTPUT_DATA] === "number") {
-                output = [buildItemSearchType(functionSearchType[OUTPUT_DATA], lowercasePaths)];
+    function buildFunctionSearchTypeCallback(lowercasePaths) {
+        return functionSearchType => {
+            if (functionSearchType === 0) {
+                return null;
+            }
+            const INPUTS_DATA = 0;
+            const OUTPUT_DATA = 1;
+            let inputs, output;
+            if (typeof functionSearchType[INPUTS_DATA] === "number") {
+                inputs = [buildItemSearchType(functionSearchType[INPUTS_DATA], lowercasePaths)];
             } else {
-                output = buildItemSearchTypeAll(
-                    functionSearchType[OUTPUT_DATA],
-                    lowercasePaths
+                inputs = buildItemSearchTypeAll(
+                    functionSearchType[INPUTS_DATA],
+                    lowercasePaths,
                 );
             }
-        } else {
-            output = [];
-        }
-        const where_clause = [];
-        const l = functionSearchType.length;
-        for (let i = 2; i < l; ++i) {
-            where_clause.push(typeof functionSearchType[i] === "number"
-                ? [buildItemSearchType(functionSearchType[i], lowercasePaths)]
-                : buildItemSearchTypeAll(functionSearchType[i], lowercasePaths));
-        }
-        const ret = {
-            inputs, output, where_clause,
+            if (functionSearchType.length > 1) {
+                if (typeof functionSearchType[OUTPUT_DATA] === "number") {
+                    output = [buildItemSearchType(functionSearchType[OUTPUT_DATA], lowercasePaths)];
+                } else {
+                    output = buildItemSearchTypeAll(
+                        functionSearchType[OUTPUT_DATA],
+                        lowercasePaths,
+                    );
+                }
+            } else {
+                output = [];
+            }
+            const where_clause = [];
+            const l = functionSearchType.length;
+            for (let i = 2; i < l; ++i) {
+                where_clause.push(typeof functionSearchType[i] === "number"
+                    ? [buildItemSearchType(functionSearchType[i], lowercasePaths)]
+                    : buildItemSearchTypeAll(functionSearchType[i], lowercasePaths));
+            }
+            return {
+                inputs, output, where_clause,
+            };
         };
-        itemFunctionDecoder.backrefQueue.unshift(ret);
-        if (itemFunctionDecoder.backrefQueue.length > 16) {
-            itemFunctionDecoder.backrefQueue.pop();
-        }
-        return ret;
     }
 
     /**
@@ -3245,6 +3218,185 @@ ${item.displayPath}<span class="${type}">${name}</span>\
         return functionTypeFingerprint[(fullId * 4) + 3];
     }
 
+    class VlqHexDecoder {
+        constructor(string, cons) {
+            this.string = string;
+            this.cons = cons;
+            this.offset = 0;
+            this.backrefQueue = [];
+        }
+        // call after consuming `{`
+        decodeList() {
+            const cb = "}".charCodeAt(0);
+            let c = this.string.charCodeAt(this.offset);
+            const ret = [];
+            while (c !== cb) {
+                ret.push(this.decode());
+                c = this.string.charCodeAt(this.offset);
+            }
+            this.offset += 1; // eat cb
+            return ret;
+        }
+        // consumes and returns a list or integer
+        decode() {
+            const [ob, la] = ["{", "`"].map(c => c.charCodeAt(0));
+            let n = 0;
+            let c = this.string.charCodeAt(this.offset);
+            if (c === ob) {
+                this.offset += 1;
+                return this.decodeList();
+            }
+            while (c < la) {
+                n = (n << 4) | (c & 0xF);
+                this.offset += 1;
+                c = this.string.charCodeAt(this.offset);
+            }
+            // last character >= la
+            n = (n << 4) | (c & 0xF);
+            const [sign, value] = [n & 1, n >> 1];
+            this.offset += 1;
+            return sign ? -value : value;
+        }
+        next() {
+            const c = this.string.charCodeAt(this.offset);
+            const [zero, ua, la] = ["0", "@", "`"].map(c => c.charCodeAt(0));
+            // sixteen characters after "0" are backref
+            if (c >= zero && c < ua) {
+                this.offset += 1;
+                return this.backrefQueue[c - zero];
+            }
+            // special exception: 0 doesn't use backref encoding
+            // it's already one character, and it's always nullish
+            if (c === la) {
+                this.offset += 1;
+                return this.cons(0);
+            }
+            const result = this.cons(this.decode());
+            this.backrefQueue.unshift(result);
+            if (this.backrefQueue.length > 16) {
+                this.backrefQueue.pop();
+            }
+            return result;
+        }
+    }
+    class RoaringBitmap {
+        constructor(str) {
+            const strdecoded = atob(str);
+            const u8array = new Uint8Array(strdecoded.length);
+            for (let j = 0; j < strdecoded.length; ++j) {
+                u8array[j] = strdecoded.charCodeAt(j);
+            }
+            const has_runs = u8array[0] === 0x3b;
+            const size = has_runs ?
+                ((u8array[2] | (u8array[3] << 8)) + 1) :
+                ((u8array[4] | (u8array[5] << 8) | (u8array[6] << 16) | (u8array[7] << 24)));
+            let i = has_runs ? 4 : 8;
+            let is_run;
+            if (has_runs) {
+                const is_run_len = Math.floor((size + 7) / 8);
+                is_run = u8array.slice(i, i + is_run_len);
+                i += is_run_len;
+            } else {
+                is_run = new Uint8Array();
+            }
+            this.keys = [];
+            this.cardinalities = [];
+            for (let j = 0; j < size; ++j) {
+                this.keys.push(u8array[i] | (u8array[i + 1] << 8));
+                i += 2;
+                this.cardinalities.push((u8array[i] | (u8array[i + 1] << 8)) + 1);
+                i += 2;
+            }
+            this.containers = [];
+            let offsets = null;
+            if (!has_runs || this.keys.length >= 4) {
+                offsets = [];
+                for (let j = 0; j < size; ++j) {
+                    offsets.push(u8array[i] | (u8array[i + 1] << 8) | (u8array[i + 2] << 16) |
+                        (u8array[i + 3] << 24));
+                    i += 4;
+                }
+            }
+            for (let j = 0; j < size; ++j) {
+                if (offsets && offsets[j] !== i) {
+                    console.log(this.containers);
+                    throw new Error(`corrupt bitmap ${j}: ${i} / ${offsets[j]}`);
+                }
+                if (is_run[j >> 3] & (1 << (j & 0x7))) {
+                    const runcount = (u8array[i] | (u8array[i + 1] << 8));
+                    i += 2;
+                    this.containers.push(new RoaringBitmapRun(
+                        runcount,
+                        u8array.slice(i, i + (runcount * 4)),
+                    ));
+                    i += runcount * 4;
+                } else if (this.cardinalities[j] >= 4096) {
+                    this.containers.push(new RoaringBitmapBits(u8array.slice(i, i + 8192)));
+                    i += 8192;
+                } else {
+                    const end = this.cardinalities[j] * 2;
+                    this.containers.push(new RoaringBitmapArray(
+                        this.cardinalities[j],
+                        u8array.slice(i, i + end),
+                    ));
+                    i += end;
+                }
+            }
+        }
+        contains(keyvalue) {
+            const key = keyvalue >> 16;
+            const value = keyvalue & 0xFFFF;
+            for (let i = 0; i < this.keys.length; ++i) {
+                if (this.keys[i] === key) {
+                    return this.containers[i].contains(value);
+                }
+            }
+            return false;
+        }
+    }
+
+    class RoaringBitmapRun {
+        constructor(runcount, array) {
+            this.runcount = runcount;
+            this.array = array;
+        }
+        contains(value) {
+            const l = this.runcount * 4;
+            for (let i = 0; i < l; i += 4) {
+                const start = this.array[i] | (this.array[i + 1] << 8);
+                const lenm1 = this.array[i + 2] | (this.array[i + 3] << 8);
+                if (value >= start && value <= (start + lenm1)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+    class RoaringBitmapArray {
+        constructor(cardinality, array) {
+            this.cardinality = cardinality;
+            this.array = array;
+        }
+        contains(value) {
+            const l = this.cardinality * 2;
+            for (let i = 0; i < l; i += 2) {
+                const start = this.array[i] | (this.array[i + 1] << 8);
+                if (value === start) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+    class RoaringBitmapBits {
+        constructor(array) {
+            this.array = array;
+        }
+        contains(value) {
+            return !!(this.array[value >> 3] & (1 << (value & 7)));
+        }
+    }
+
     /**
      * Convert raw search index into in-memory search index.
      *
@@ -3252,6 +3404,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\
      */
     function buildIndex(rawSearchIndex) {
         searchIndex = [];
+        searchIndexDeprecated = new Map();
+        searchIndexEmptyDesc = new Map();
         const charA = "A".charCodeAt(0);
         let currentIndex = 0;
         let id = 0;
@@ -3271,26 +3425,48 @@ ${item.displayPath}<span class="${type}">${name}</span>\
         id = 0;
 
         for (const [crate, crateCorpus] of rawSearchIndex) {
+            // a string representing the lengths of each description shard
+            // a string representing the list of function types
+            const itemDescShardDecoder = new VlqHexDecoder(crateCorpus.D, noop => noop);
+            let descShard = {
+                crate,
+                shard: 0,
+                start: 0,
+                len: itemDescShardDecoder.next(),
+                promise: null,
+                resolve: null,
+            };
+            const descShardList = [ descShard ];
+
+            // Deprecated items and items with no description
+            searchIndexDeprecated.set(crate, new RoaringBitmap(crateCorpus.c));
+            searchIndexEmptyDesc.set(crate, new RoaringBitmap(crateCorpus.e));
+            let descIndex = 0;
+
             // This object should have exactly the same set of fields as the "row"
             // object defined below. Your JavaScript runtime will thank you.
             // https://mathiasbynens.be/notes/shapes-ics
             const crateRow = {
-                crate: crate,
+                crate,
                 ty: 3, // == ExternCrate
                 name: crate,
                 path: "",
-                desc: crateCorpus.doc,
+                descShard,
+                descIndex,
                 parent: undefined,
                 type: null,
-                id: id,
+                id,
                 word: crate,
                 normalizedName: crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, ""),
-                deprecated: null,
+                bitIndex: 0,
                 implDisambiguator: null,
             };
             id += 1;
             searchIndex.push(crateRow);
             currentIndex += 1;
+            if (!searchIndexEmptyDesc.get(crate).contains(0)) {
+                descIndex += 1;
+            }
 
             // a String of one character item type codes
             const itemTypes = crateCorpus.t;
@@ -3302,19 +3478,9 @@ ${item.displayPath}<span class="${type}">${name}</span>\
             // i.e. if indices 4 and 11 are present, but 5-10 and 12-13 are not present,
             // 5-10 will fall back to the path for 4 and 12-13 will fall back to the path for 11
             const itemPaths = new Map(crateCorpus.q);
-            // an array of (String) descriptions
-            const itemDescs = crateCorpus.d;
             // an array of (Number) the parent path index + 1 to `paths`, or 0 if none
             const itemParentIdxs = crateCorpus.i;
-            // a string representing the list of function types
-            const itemFunctionDecoder = {
-                string: crateCorpus.f,
-                offset: 0,
-                backrefQueue: [],
-            };
-            // an array of (Number) indices for the deprecated items
-            const deprecatedItems = new Set(crateCorpus.c);
-            // an array of (Number) indices for the deprecated items
+            // a map Number, string for impl disambiguators
             const implDisambiguator = new Map(crateCorpus.b);
             // an array of [(Number) item type,
             //              (String) name]
@@ -3326,6 +3492,12 @@ ${item.displayPath}<span class="${type}">${name}</span>\
             // an array of [{name: String, ty: Number}]
             const lowercasePaths = [];
 
+            // a string representing the list of function types
+            const itemFunctionDecoder = new VlqHexDecoder(
+                crateCorpus.f,
+                buildFunctionSearchTypeCallback(lowercasePaths),
+            );
+
             // convert `rawPaths` entries into object form
             // generate normalizedPaths for function search mode
             let len = paths.length;
@@ -3354,12 +3526,26 @@ ${item.displayPath}<span class="${type}">${name}</span>\
             lastPath = "";
             len = itemTypes.length;
             for (let i = 0; i < len; ++i) {
+                const bitIndex = i + 1;
+                if (descIndex >= descShard.len &&
+                    !searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
+                    descShard = {
+                        crate,
+                        shard: descShard.shard + 1,
+                        start: descShard.start + descShard.len,
+                        len: itemDescShardDecoder.next(),
+                        promise: null,
+                        resolve: null,
+                    };
+                    descIndex = 0;
+                    descShardList.push(descShard);
+                }
                 let word = "";
                 if (typeof itemNames[i] === "string") {
                     word = itemNames[i].toLowerCase();
                 }
                 const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath;
-                const type = buildFunctionSearchType(itemFunctionDecoder, lowercasePaths);
+                const type = itemFunctionDecoder.next();
                 if (type !== null) {
                     if (type) {
                         const fp = functionTypeFingerprint.subarray(id * 4, (id + 1) * 4);
@@ -3380,22 +3566,26 @@ ${item.displayPath}<span class="${type}">${name}</span>\
                 // This object should have exactly the same set of fields as the "crateRow"
                 // object defined above.
                 const row = {
-                    crate: crate,
+                    crate,
                     ty: itemTypes.charCodeAt(i) - charA,
                     name: itemNames[i],
-                    path: path,
-                    desc: itemDescs[i],
+                    path,
+                    descShard,
+                    descIndex,
                     parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined,
                     type,
-                    id: id,
+                    id,
                     word,
                     normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""),
-                    deprecated: deprecatedItems.has(i),
+                    bitIndex,
                     implDisambiguator: implDisambiguator.has(i) ? implDisambiguator.get(i) : null,
                 };
                 id += 1;
                 searchIndex.push(row);
                 lastPath = row.path;
+                if (!searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
+                    descIndex += 1;
+                }
             }
 
             if (aliases) {
@@ -3419,6 +3609,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
                 }
             }
             currentIndex += itemTypes.length;
+            searchState.descShards.set(crate, descShardList);
         }
         // Drop the (rather large) hash table used for reusing function items
         TYPES_POOL = new Map();
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index bda7b3c647e..73c543567c0 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -211,14 +211,14 @@ function updateSidebarWidth() {
     if (desktopSidebarWidth && desktopSidebarWidth !== "null") {
         document.documentElement.style.setProperty(
             "--desktop-sidebar-width",
-            desktopSidebarWidth + "px"
+            desktopSidebarWidth + "px",
         );
     }
     const srcSidebarWidth = getSettingValue("src-sidebar-width");
     if (srcSidebarWidth && srcSidebarWidth !== "null") {
         document.documentElement.style.setProperty(
             "--src-sidebar-width",
-            srcSidebarWidth + "px"
+            srcSidebarWidth + "px",
         );
     }
 }
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 499a61ce7a0fc6a72040084862a68b2603e770e
+Subproject 0637083df5bbdcc951845f0d2eff6999cdb6d30
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index cabebf89bec..325c9bee057 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -112,7 +112,7 @@ fn check_rvalue<'tcx>(
         Rvalue::Repeat(operand, _)
         | Rvalue::Use(operand)
         | Rvalue::Cast(
-            CastKind::PointerFromExposedAddress
+            CastKind::PointerWithExposedProvenance
             | CastKind::IntToInt
             | CastKind::FloatToInt
             | CastKind::IntToFloat
@@ -149,7 +149,7 @@ fn check_rvalue<'tcx>(
                 Err((span, "unsizing casts are not allowed in const fn".into()))
             }
         },
-        Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
+        Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => {
             Err((span, "casting pointers to ints is unstable in const fn".into()))
         },
         Rvalue::Cast(CastKind::DynStar, _, _) => {
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index b791b38379f..1624e2a6084 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -571,7 +571,9 @@ pub fn make_tests(
         &modified_tests,
         &mut poisoned,
     )
-    .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display()));
+    .unwrap_or_else(|reason| {
+        panic!("Could not read tests from {}: {reason}", config.src_base.display())
+    });
 
     if poisoned {
         eprintln!();
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index 041254e6f43..9d24d3c6f47 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -59,6 +59,7 @@ harness = false
 [features]
 default = ["stack-cache"]
 stack-cache = []
+stack-cache-consistency-check = ["stack-cache"]
 
 # Be aware that this file is inside a workspace when used via the
 # submodule in the rustc repo. That means there are many cargo features
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 26e55b89708..11b77780833 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -324,7 +324,7 @@ environment variable. We first document the most relevant and most commonly used
   number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in
   any way.
 * `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and
-  [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html).
+  [`ptr::with_exposed_provenance`](https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html).
   This will necessarily miss some bugs as those operations are not efficiently and accurately
   implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is
   subject to these operations.
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 8c0f605fd6e..694720ab21f 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -89,8 +89,12 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
     let verbose = num_arg_flag("-v");
 
     // Determine the involved architectures.
-    let rustc_version = VersionMeta::for_command(miri_for_host())
-        .expect("failed to determine underlying rustc version of Miri");
+    let rustc_version = VersionMeta::for_command(miri_for_host()).unwrap_or_else(|err| {
+        panic!(
+            "failed to determine underlying rustc version of Miri ({:?}):\n{err:?}",
+            miri_for_host()
+        )
+    });
     let host = &rustc_version.host;
     let target = get_arg_flag_value("--target");
     let target = target.as_ref().unwrap_or(host);
@@ -179,18 +183,27 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
         );
     }
     cmd.env("RUSTC_WRAPPER", &cargo_miri_path);
+    // There's also RUSTC_WORKSPACE_WRAPPER, which gets in the way of our own wrapping.
+    if env::var_os("RUSTC_WORKSPACE_WRAPPER").is_some() {
+        println!(
+            "WARNING: Ignoring `RUSTC_WORKSPACE_WRAPPER` environment variable, Miri does not support wrapping."
+        );
+    }
+    cmd.env_remove("RUSTC_WORKSPACE_WRAPPER");
     // We are going to invoke `MIRI` for everything, not `RUSTC`.
     if env::var_os("RUSTC").is_some() && env::var_os("MIRI").is_none() {
         println!(
             "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver."
         );
     }
-    // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke
-    // `rustc` even when `RUSTC_WRAPPER` is set. To make sure everything is coherent, we want that
-    // to be the Miri driver, but acting as rustc, on the target level. (Target, rather than host,
-    // is needed for cross-interpretation situations.) This is not a perfect emulation of real rustc
-    // (it might be unable to produce binaries since the sysroot is check-only), but it's as close
-    // as we can get, and it's good enough for autocfg.
+    // Ideally we would set RUSTC to some non-existent path, so we can be sure our wrapping is
+    // always applied. However, buggy build scripts (https://github.com/eyre-rs/eyre/issues/84) and
+    // also cargo (https://github.com/rust-lang/cargo/issues/10885) will invoke `rustc` even when
+    // `RUSTC_WRAPPER` is set, bypassing the wrapper. To make sure everything is coherent, we want
+    // that to be the Miri driver, but acting as rustc, on the target level. (Target, rather than
+    // host, is needed for cross-interpretation situations.) This is not a perfect emulation of real
+    // rustc (it might be unable to produce binaries since the sysroot is check-only), but it's as
+    // close as we can get, and it's good enough for autocfg.
     //
     // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc
     // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that
@@ -213,7 +226,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
     }
 
     // Run cargo.
-    debug_cmd("[cargo-miri miri]", verbose, &cmd);
+    debug_cmd("[cargo-miri cargo]", verbose, &cmd);
     exec(cmd)
 }
 
@@ -247,6 +260,16 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
     /// Cargo does not give us this information directly, so we need to check
     /// various command-line flags.
     fn is_runnable_crate() -> bool {
+        // Determine whether this is cargo invoking rustc to get some infos. Ideally we'd check "is
+        // there a filename passed to rustc", but that's very hard as we would have to know whether
+        // e.g. `--print foo` is a booolean flag `--print` followed by filename `foo` or equivalent
+        // to `--print=foo`. So instead we use this more fragile approach of detecting the presence
+        // of a "query" flag rather than the absence of a filename.
+        let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV");
+        if info_query {
+            // Nothing to run.
+            return false;
+        }
         let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin";
         let is_test = has_arg_flag("--test");
         is_bin || is_test
@@ -285,16 +308,9 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
         }
     }
 
-    // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver;
-    // however, if we get called back by cargo here, we'll carefully compute the right flags
-    // ourselves, so we first un-do what the earlier phase did.
-    env::remove_var("MIRI_BE_RUSTC");
-
     let verbose = std::env::var("MIRI_VERBOSE")
         .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer"));
     let target_crate = is_target_crate();
-    // Determine whether this is cargo invoking rustc to get some infos.
-    let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV");
 
     let store_json = |info: CrateRunInfo| {
         if get_arg_flag_value("--emit").unwrap_or_default().split(',').any(|e| e == "dep-info") {
@@ -321,7 +337,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
         }
     };
 
-    let runnable_crate = !info_query && is_runnable_crate();
+    let runnable_crate = is_runnable_crate();
 
     if runnable_crate && target_crate {
         assert!(
@@ -395,7 +411,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
     let mut emit_link_hack = false;
     // Arguments are treated very differently depending on whether this crate is
     // for interpretation by Miri, or for use by a build script / proc macro.
-    if !info_query && target_crate {
+    if target_crate {
         // Forward arguments, but remove "link" from "--emit" to make this a check-only build.
         let emit_flag = "--emit";
         while let Some(arg) = args.next() {
@@ -429,17 +445,14 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
             cmd.arg("-C").arg("panic=abort");
         }
     } else {
-        // For host crates (but not when we are just printing some info),
-        // we might still have to set the sysroot.
-        if !info_query {
-            // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly
-            // due to bootstrap complications.
-            if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") {
-                cmd.arg("--sysroot").arg(sysroot);
-            }
+        // This is a host crate.
+        // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly
+        // due to bootstrap complications.
+        if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") {
+            cmd.arg("--sysroot").arg(sysroot);
         }
 
-        // For host crates or when we are printing, just forward everything.
+        // Forward everything.
         cmd.args(args);
     }
 
@@ -451,9 +464,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
 
     // Run it.
     if verbose > 0 {
-        eprintln!(
-            "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} info_query={info_query}"
-        );
+        eprintln!("[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate}");
     }
 
     // Create a stub .rlib file if "link" was requested by cargo.
@@ -480,11 +491,6 @@ pub enum RunnerPhase {
 }
 
 pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: RunnerPhase) {
-    // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver;
-    // however, if we get called back by cargo here, we'll carefully compute the right flags
-    // ourselves, so we first un-do what the earlier phase did.
-    env::remove_var("MIRI_BE_RUSTC");
-
     let verbose = std::env::var("MIRI_VERBOSE")
         .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer"));
 
@@ -542,15 +548,13 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
     // but when we run here, cargo does not interpret the JSON any more. `--json`
     // then also needs to be dropped.
     let mut args = info.args.into_iter();
-    let error_format_flag = "--error-format";
-    let json_flag = "--json";
     while let Some(arg) = args.next() {
         if arg == "--extern" {
             forward_patched_extern_arg(&mut args, &mut cmd);
-        } else if let Some(suffix) = arg.strip_prefix(error_format_flag) {
+        } else if let Some(suffix) = arg.strip_prefix("--error-format") {
             assert!(suffix.starts_with('='));
             // Drop this argument.
-        } else if let Some(suffix) = arg.strip_prefix(json_flag) {
+        } else if let Some(suffix) = arg.strip_prefix("--json") {
             assert!(suffix.starts_with('='));
             // Drop this argument.
         } else {
@@ -589,13 +593,11 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
     let rustdoc = env::var("MIRI_ORIG_RUSTDOC").unwrap_or("rustdoc".to_string());
     let mut cmd = Command::new(rustdoc);
 
-    let extern_flag = "--extern";
-    let runtool_flag = "--runtool";
     while let Some(arg) = args.next() {
-        if arg == extern_flag {
+        if arg == "--extern" {
             // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files.
             forward_patched_extern_arg(&mut args, &mut cmd);
-        } else if arg == runtool_flag {
+        } else if arg == "--runtool" {
             // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support.
             // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag;
             // otherwise, we won't be called as rustdoc at all.
diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs
index a98e1fcd485..401e9158fae 100644
--- a/src/tools/miri/cargo-miri/src/setup.rs
+++ b/src/tools/miri/cargo-miri/src/setup.rs
@@ -90,13 +90,13 @@ pub fn setup(
     let cargo_cmd = {
         let mut command = cargo();
         // Use Miri as rustc to build a libstd compatible with us (and use the right flags).
+        // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags
+        // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves).
+        // The `MIRI_CALLED_FROM_SETUP` will mean we dispatch to `phase_setup_rustc`.
         // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`,
         // because we still need bootstrap to distinguish between host and target crates.
         // In that case we overwrite `RUSTC_REAL` instead which determines the rustc used
         // for target crates.
-        // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags
-        // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves).
-        // The `MIRI_CALLED_FROM_SETUP` will mean we dispatch to `phase_setup_rustc`.
         let cargo_miri_path = std::env::current_exe().expect("current executable path invalid");
         if env::var_os("RUSTC_STAGE").is_some() {
             assert!(env::var_os("RUSTC").is_some());
diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs
index 6c1a074cd8c..d99957d9c22 100644
--- a/src/tools/miri/cargo-miri/src/util.rs
+++ b/src/tools/miri/cargo-miri/src/util.rs
@@ -101,7 +101,12 @@ pub fn find_miri() -> PathBuf {
 }
 
 pub fn miri() -> Command {
-    Command::new(find_miri())
+    let mut cmd = Command::new(find_miri());
+    // We never want to inherit this from the environment.
+    // However, this is sometimes set in the environment to work around build scripts that don't
+    // honor RUSTC_WRAPPER. So remove it again in case it is set.
+    cmd.env_remove("MIRI_BE_RUSTC");
+    cmd
 }
 
 pub fn miri_for_host() -> Command {
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 54c5d3087fd..cccf10a7d70 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -22,17 +22,24 @@ if [ "$HOST_TARGET" = i686-pc-windows-msvc ]; then
   BASH="C:/Program Files/Git/usr/bin/bash"
 fi
 
-# Determine configuration for installed build
-echo "Installing release version of Miri"
+# Global configuration
 export RUSTFLAGS="-D warnings"
 export CARGO_INCREMENTAL=0
 export CARGO_EXTRA_FLAGS="--locked"
+
+# Determine configuration for installed build
+echo "Installing release version of Miri"
 ./miri install
 
-# Prepare debug build for direct `./miri` invocations
-echo "Building debug version of Miri"
+echo "Checking various feature flag configurations"
 ./miri check --no-default-features # make sure this can be built
-./miri check --all-features # and this, too
+./miri check # and this, too
+# `--all-features` is used for the build below, so no extra check needed.
+
+# Prepare debug build for direct `./miri` invocations.
+# We enable all features to make sure the Stacked Borrows consistency check runs.
+echo "Building debug version of Miri"
+export CARGO_EXTRA_FLAGS="$CARGO_EXTRA_FLAGS --all-features"
 ./miri build --all-targets # the build that all the `./miri test` below will use
 
 endgroup
@@ -46,8 +53,8 @@ function run_tests {
   fi
 
   ## ui test suite
-  # On the host and on Linux, also stress-test the GC.
-  if [ -z "${MIRI_TEST_TARGET:-}" ] || [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then
+  # On the host, also stress-test the GC.
+  if [ -z "${MIRI_TEST_TARGET:-}" ]; then
     MIRIFLAGS="${MIRIFLAGS:-} -Zmiri-provenance-gc=1" ./miri test
   else
     ./miri test
@@ -130,6 +137,8 @@ case $HOST_TARGET in
     MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
     MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
     MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
+    MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests
+    MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests
     # Some targets are only partially supported.
     MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align num_cpus
     MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align num_cpus
@@ -145,9 +154,7 @@ case $HOST_TARGET in
     MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests
     ;;
   i686-pc-windows-msvc)
-    MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests
     MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests
-    MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests
     ;;
   *)
     echo "FATAL: unknown OS"
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 66f323290b2..58deac66560 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -479,10 +479,11 @@ impl Command {
         Ok(())
     }
 
-    fn run(dep: bool, flags: Vec<OsString>) -> Result<()> {
+    fn run(dep: bool, mut flags: Vec<OsString>) -> Result<()> {
         let mut e = MiriEnv::new()?;
         // Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so
-        // that we set the MIRI_SYSROOT up the right way.
+        // that we set the MIRI_SYSROOT up the right way. We must make sure that
+        // MIRI_TEST_TARGET and `--target` are in sync.
         use itertools::Itertools;
         let target = flags
             .iter()
@@ -493,33 +494,35 @@ impl Command {
             // Found it!
             e.sh.set_var("MIRI_TEST_TARGET", target);
         } else if let Ok(target) = std::env::var("MIRI_TEST_TARGET") {
-            // Make sure miri actually uses this target.
-            let miriflags = e.sh.var("MIRIFLAGS").unwrap_or_default();
-            e.sh.set_var("MIRIFLAGS", format!("{miriflags} --target {target}"));
+            // Convert `MIRI_TEST_TARGET` into `--target`.
+            flags.push("--target".into());
+            flags.push(target.into());
         }
-        // Scan for "--edition" (we'll set one ourselves if that flag is not present).
+        // Scan for "--edition", set one ourselves if that flag is not present.
         let have_edition =
             flags.iter().take_while(|arg| *arg != "--").any(|arg| *arg == "--edition");
+        if !have_edition {
+            flags.push("--edition=2021".into()); // keep in sync with `tests/ui.rs`.`
+        }
 
         // Prepare a sysroot.
         e.build_miri_sysroot(/* quiet */ true)?;
 
-        // Then run the actual command.
+        // Then run the actual command. Also add MIRIFLAGS.
         let miri_manifest = path!(e.miri_dir / "Cargo.toml");
         let miri_flags = e.sh.var("MIRIFLAGS").unwrap_or_default();
         let miri_flags = flagsplit(&miri_flags);
         let toolchain = &e.toolchain;
         let extra_flags = &e.cargo_extra_flags;
-        let edition_flags = (!have_edition).then_some("--edition=2021"); // keep in sync with `tests/ui.rs`.`
         if dep {
             cmd!(
                 e.sh,
-                "cargo +{toolchain} --quiet test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode {miri_flags...} {edition_flags...} {flags...}"
+                "cargo +{toolchain} --quiet test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode {miri_flags...} {flags...}"
             ).quiet().run()?;
         } else {
             cmd!(
                 e.sh,
-                "cargo +{toolchain} --quiet run {extra_flags...} --manifest-path {miri_manifest} -- {miri_flags...} {edition_flags...} {flags...}"
+                "cargo +{toolchain} --quiet run {extra_flags...} --manifest-path {miri_manifest} -- {miri_flags...} {flags...}"
             ).quiet().run()?;
         }
         Ok(())
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index fa06a069d54..187756851c7 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-cb7c63606e53715f94f3ba04d38e50772e4cd23d
+5baf1e13f568b61e121953bf6a3d09faee7dd446
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index e1714aa9e46..fec39ec2b8e 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -18,12 +18,12 @@ use reuse_pool::ReusePool;
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum ProvenanceMode {
-    /// We support `expose_addr`/`from_exposed_addr` via "wildcard" provenance.
-    /// However, we want on `from_exposed_addr` to alert the user of the precision loss.
+    /// We support `expose_provenance`/`with_exposed_provenance` via "wildcard" provenance.
+    /// However, we warn on `with_exposed_provenance` to alert the user of the precision loss.
     Default,
     /// Like `Default`, but without the warning.
     Permissive,
-    /// We error on `from_exposed_addr`, ensuring no precision loss.
+    /// We error on `with_exposed_provenance`, ensuring no precision loss.
     Strict,
 }
 
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
index 712c26a9afd..76430498e2b 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
@@ -146,7 +146,7 @@ impl<'tcx> Stack {
     /// Panics if any of the caching mechanisms have broken,
     /// - The StackCache indices don't refer to the parallel items,
     /// - There are no Unique items outside of first_unique..last_unique
-    #[cfg(all(feature = "stack-cache", debug_assertions))]
+    #[cfg(feature = "stack-cache-consistency-check")]
     fn verify_cache_consistency(&self) {
         // Only a full cache needs to be valid. Also see the comments in find_granting_cache
         // and set_unknown_bottom.
@@ -190,7 +190,7 @@ impl<'tcx> Stack {
         tag: ProvenanceExtra,
         exposed_tags: &FxHashSet<BorTag>,
     ) -> Result<Option<usize>, ()> {
-        #[cfg(all(feature = "stack-cache", debug_assertions))]
+        #[cfg(feature = "stack-cache-consistency-check")]
         self.verify_cache_consistency();
 
         let ProvenanceExtra::Concrete(tag) = tag else {
@@ -327,7 +327,7 @@ impl<'tcx> Stack {
         // This primes the cache for the next access, which is almost always the just-added tag.
         self.cache.add(new_idx, new);
 
-        #[cfg(debug_assertions)]
+        #[cfg(feature = "stack-cache-consistency-check")]
         self.verify_cache_consistency();
     }
 
@@ -410,7 +410,7 @@ impl<'tcx> Stack {
             self.unique_range.end = self.unique_range.end.min(disable_start);
         }
 
-        #[cfg(all(feature = "stack-cache", debug_assertions))]
+        #[cfg(feature = "stack-cache-consistency-check")]
         self.verify_cache_consistency();
 
         Ok(())
@@ -465,7 +465,7 @@ impl<'tcx> Stack {
             self.unique_range = 0..0;
         }
 
-        #[cfg(all(feature = "stack-cache", debug_assertions))]
+        #[cfg(feature = "stack-cache-consistency-check")]
         self.verify_cache_consistency();
         Ok(())
     }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index 4394e3c2c86..2690bc026a1 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -365,7 +365,7 @@ type S = &'static str;
 /// Pretty-printing details
 ///
 /// Example:
-/// ```
+/// ```rust,ignore (private type)
 /// DisplayFmtWrapper {
 ///     top: '>',
 ///     bot: '<',
@@ -393,7 +393,7 @@ struct DisplayFmtWrapper {
 /// Formating of the permissions on each range.
 ///
 /// Example:
-/// ```
+/// ```rust,ignore (private type)
 /// DisplayFmtPermission {
 ///     open: "[",
 ///     sep: "|",
@@ -425,7 +425,7 @@ struct DisplayFmtPermission {
 /// Formating of the tree structure.
 ///
 /// Example:
-/// ```
+/// ```rust,ignore (private type)
 /// DisplayFmtPadding {
 ///     join_middle: "|-",
 ///     join_last: "'-",
@@ -463,7 +463,7 @@ struct DisplayFmtPadding {
 /// How to show whether a location has been accessed
 ///
 /// Example:
-/// ```
+/// ```rust,ignore (private type)
 /// DisplayFmtAccess {
 ///     yes: " ",
 ///     no: "?",
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
index 5c7f5ea46ba..bec51c7cdf2 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -181,8 +181,12 @@ impl Permission {
     pub fn is_initial(&self) -> bool {
         self.inner.is_initial()
     }
+    /// Check if `self` is the terminal state of a pointer (is `Disabled`).
+    pub fn is_disabled(&self) -> bool {
+        self.inner == Disabled
+    }
 
-    /// Default initial permission of the root of a new tree.
+    /// Default initial permission of the root of a new tree at inbounds positions.
     /// Must *only* be used for the root, this is not in general an "initial" permission!
     pub fn new_active() -> Self {
         Self { inner: Active }
@@ -193,11 +197,17 @@ impl Permission {
         Self { inner: Reserved { ty_is_freeze, conflicted: false } }
     }
 
-    /// Default initial permission of a reborrowed shared reference
+    /// Default initial permission of a reborrowed shared reference.
     pub fn new_frozen() -> Self {
         Self { inner: Frozen }
     }
 
+    /// Default initial permission of  the root of a new tre at out-of-bounds positions.
+    /// Must *only* be used for the root, this is not in general an "initial" permission!
+    pub fn new_disabled() -> Self {
+        Self { inner: Disabled }
+    }
+
     /// Apply the transition to the inner PermissionPriv.
     pub fn perform_access(
         kind: AccessKind,
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
index dda1c7cca19..0fea78daa88 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -42,6 +42,7 @@ pub(super) struct LocationState {
     /// protected, that is *not* the case for uninitialized locations. Instead we just have a latent
     /// "future initial permission" of `Disabled`, causing UB only if an access is ever actually
     /// performed.
+    /// Note that the tree root is also always initialized, as if the allocation was a write access.
     initialized: bool,
     /// This pointer's current permission / future initial permission.
     permission: Permission,
@@ -55,17 +56,18 @@ pub(super) struct LocationState {
 }
 
 impl LocationState {
-    /// Default initial state has never been accessed and has been subjected to no
-    /// foreign access.
-    fn new(permission: Permission) -> Self {
+    /// Constructs a new initial state. It has neither been accessed, nor been subjected
+    /// to any foreign access yet.
+    /// The permission is not allowed to be `Active`.
+    fn new_uninit(permission: Permission) -> Self {
+        assert!(permission.is_initial() || permission.is_disabled());
         Self { permission, initialized: false, latest_foreign_access: None }
     }
 
-    /// Record that this location was accessed through a child pointer by
-    /// marking it as initialized
-    fn with_access(mut self) -> Self {
-        self.initialized = true;
-        self
+    /// Constructs a new initial state. It has not yet been subjected
+    /// to any foreign access. However, it is already marked as having been accessed.
+    fn new_init(permission: Permission) -> Self {
+        Self { permission, initialized: true, latest_foreign_access: None }
     }
 
     /// Check if the location has been initialized, i.e. if it has
@@ -238,8 +240,10 @@ pub(super) struct Node {
     /// If the pointer was reborrowed, it has children.
     // FIXME: bench to compare this to FxHashSet and to other SmallVec sizes
     pub children: SmallVec<[UniIndex; 4]>,
-    /// Either `Reserved` or `Frozen`, the permission this tag will be lazily initialized
-    /// to on the first access.
+    /// Either `Reserved`,  `Frozen`, or `Disabled`, it is the permission this tag will
+    /// lazily be initialized to on the first access.
+    /// It is only ever `Disabled` for a tree root, since the root is initialized to `Active` by
+    /// its own separate mechanism.
     default_initial_perm: Permission,
     /// Some extra information useful only for debugging purposes
     pub debug_info: NodeDebugInfo,
@@ -444,12 +448,14 @@ impl<'tree> TreeVisitor<'tree> {
 impl Tree {
     /// Create a new tree, with only a root pointer.
     pub fn new(root_tag: BorTag, size: Size, span: Span) -> Self {
-        let root_perm = Permission::new_active();
+        // The root has `Disabled` as the default permission,
+        // so that any access out of bounds is invalid.
+        let root_default_perm = Permission::new_disabled();
         let mut tag_mapping = UniKeyMap::default();
         let root_idx = tag_mapping.insert(root_tag);
         let nodes = {
             let mut nodes = UniValMap::<Node>::default();
-            let mut debug_info = NodeDebugInfo::new(root_tag, root_perm, span);
+            let mut debug_info = NodeDebugInfo::new(root_tag, root_default_perm, span);
             // name the root so that all allocations contain one named pointer
             debug_info.add_name("root of the allocation");
             nodes.insert(
@@ -458,7 +464,7 @@ impl Tree {
                     tag: root_tag,
                     parent: None,
                     children: SmallVec::default(),
-                    default_initial_perm: root_perm,
+                    default_initial_perm: root_default_perm,
                     debug_info,
                 },
             );
@@ -466,7 +472,11 @@ impl Tree {
         };
         let rperms = {
             let mut perms = UniValMap::default();
-            perms.insert(root_idx, LocationState::new(root_perm).with_access());
+            // We manually set it to `Active` on all in-bounds positions.
+            // We also ensure that it is initalized, so that no `Active` but
+            // not yet initialized nodes exist. Essentially, we pretend there
+            // was a write that initialized these to `Active`.
+            perms.insert(root_idx, LocationState::new_init(Permission::new_active()));
             RangeMap::new(size, perms)
         };
         Self { root: root_idx, nodes, rperms, tag_mapping }
@@ -500,7 +510,7 @@ impl<'tcx> Tree {
         // Register new_tag as a child of parent_tag
         self.nodes.get_mut(parent_idx).unwrap().children.push(idx);
         // Initialize perms
-        let perm = LocationState::new(default_initial_perm).with_access();
+        let perm = LocationState::new_init(default_initial_perm);
         for (_perms_range, perms) in self.rperms.iter_mut(reborrow_range.start, reborrow_range.size)
         {
             perms.insert(idx, perm);
@@ -599,7 +609,7 @@ impl<'tcx> Tree {
          -> Result<ContinueTraversal, TransitionError> {
             let NodeAppArgs { node, mut perm, rel_pos } = args;
 
-            let old_state = perm.or_insert(LocationState::new(node.default_initial_perm));
+            let old_state = perm.or_insert(LocationState::new_uninit(node.default_initial_perm));
 
             match old_state.skip_if_known_noop(access_kind, rel_pos) {
                 ContinueTraversal::SkipChildren => return Ok(ContinueTraversal::SkipChildren),
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
index 35f3b53afdb..f568850d8db 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
@@ -516,11 +516,11 @@ mod spurious_read {
         let source = LocStateProtPair {
             xy_rel: RelPosXY::MutuallyForeign,
             x: LocStateProt {
-                state: LocationState::new(Permission::new_frozen()).with_access(),
+                state: LocationState::new_init(Permission::new_frozen()),
                 prot: true,
             },
             y: LocStateProt {
-                state: LocationState::new(Permission::new_reserved(false)),
+                state: LocationState::new_uninit(Permission::new_reserved(false)),
                 prot: true,
             },
         };
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
index d9cad9c8e0b..f45b2d9e00a 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
@@ -132,7 +132,7 @@ where
     /// the associated `UniIndex` from ALL `UniValMap`s.
     ///
     /// Example of such behavior:
-    /// ```
+    /// ```rust,ignore (private type can't be doctested)
     /// let mut keymap = UniKeyMap::<char>::default();
     /// let mut valmap = UniValMap::<char>::default();
     /// // Insert 'a' -> _ -> 'A'
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index e2e18d3a734..d0d73bb1b34 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -1046,7 +1046,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     /// Run the core interpreter loop. Returns only when an interrupt occurs (an error or program
     /// termination).
     fn run_threads(&mut self) -> InterpResult<'tcx, !> {
-       let this = self.eval_context_mut();
+        let this = self.eval_context_mut();
         loop {
             if CTRL_C_RECEIVED.load(Relaxed) {
                 this.machine.handle_abnormal_termination();
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 99d37065bac..30349c003a9 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -66,7 +66,7 @@ impl fmt::Display for TerminationInfo {
             Int2PtrWithStrictProvenance =>
                 write!(
                     f,
-                    "integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`"
+                    "integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance`"
                 ),
             StackedBorrowsUb { msg, .. } => write!(f, "{msg}"),
             TreeBorrowsUb { title, .. } => write!(f, "{title}"),
@@ -593,7 +593,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
                     (
                         None,
                         format!(
-                            "This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,"
+                            "This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,"
                         ),
                     ),
                     (
@@ -603,7 +603,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
                     (
                         None,
                         format!(
-                            "See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation."
+                            "See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation."
                         ),
                     ),
                     (
@@ -615,7 +615,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
                     (
                         None,
                         format!(
-                            "You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics."
+                            "You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics."
                         ),
                     ),
                     (
diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs
index 6973c0e9c35..a2fc4f0f761 100644
--- a/src/tools/miri/src/shims/intrinsics/simd.rs
+++ b/src/tools/miri/src/shims/intrinsics/simd.rs
@@ -514,7 +514,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     dest.transmute(this.machine.layouts.uint(dest.layout.size).unwrap(), this)?;
                 this.write_int(res, &dest)?;
             }
-            "cast" | "as" | "cast_ptr" | "expose_addr" | "from_exposed_addr" => {
+            "cast" | "as" | "cast_ptr" | "expose_provenance" | "with_exposed_provenance" => {
                 let [op] = check_arg_count(args)?;
                 let (op, op_len) = this.operand_to_simd(op)?;
                 let (dest, dest_len) = this.mplace_to_simd(dest)?;
@@ -524,8 +524,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let unsafe_cast = intrinsic_name == "cast";
                 let safe_cast = intrinsic_name == "as";
                 let ptr_cast = intrinsic_name == "cast_ptr";
-                let expose_cast = intrinsic_name == "expose_addr";
-                let from_exposed_cast = intrinsic_name == "from_exposed_addr";
+                let expose_cast = intrinsic_name == "expose_provenance";
+                let from_exposed_cast = intrinsic_name == "with_exposed_provenance";
 
                 for i in 0..dest_len {
                     let op = this.read_immediate(&this.project_index(&op, i)?)?;
@@ -557,9 +557,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                             this.ptr_to_ptr(&op, dest.layout)?,
                         // Ptr/Int casts
                         (ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) if expose_cast =>
-                            this.pointer_expose_address_cast(&op, dest.layout)?,
+                            this.pointer_expose_provenance_cast(&op, dest.layout)?,
                         (ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast =>
-                            this.pointer_from_exposed_address_cast(&op, dest.layout)?,
+                            this.pointer_with_exposed_provenance_cast(&op, dest.layout)?,
                         // Error otherwise
                         _ =>
                             throw_unsup_format!(
diff --git a/src/tools/miri/test-cargo-miri/Cargo.lock b/src/tools/miri/test-cargo-miri/Cargo.lock
index f75d68f4e29..4783f79ea8f 100644
--- a/src/tools/miri/test-cargo-miri/Cargo.lock
+++ b/src/tools/miri/test-cargo-miri/Cargo.lock
@@ -3,16 +3,10 @@
 version = 3
 
 [[package]]
-name = "anyhow"
-version = "1.0.81"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
-
-[[package]]
 name = "autocfg"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
 
 [[package]]
 name = "byteorder"
@@ -22,33 +16,33 @@ checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
 
 [[package]]
 name = "byteorder"
-version = "1.4.3"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cargo-miri-test"
 version = "0.1.0"
 dependencies = [
- "anyhow",
  "autocfg",
  "byteorder 0.5.3",
- "byteorder 1.4.3",
+ "byteorder 1.5.0",
  "cdylib",
  "exported_symbol",
+ "eyre",
  "issue_1567",
  "issue_1691",
  "issue_1705",
- "issue_1760",
  "issue_rust_86261",
- "serde_derive",
+ "proc-macro2",
+ "proc_macro_crate",
 ]
 
 [[package]]
 name = "cdylib"
 version = "0.1.0"
 dependencies = [
- "byteorder 1.4.3",
+ "byteorder 1.5.0",
 ]
 
 [[package]]
@@ -63,10 +57,26 @@ name = "exported_symbol_dep"
 version = "0.1.0"
 
 [[package]]
+name = "eyre"
+version = "0.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"
+dependencies = [
+ "indenter",
+ "once_cell",
+]
+
+[[package]]
+name = "indenter"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
+
+[[package]]
 name = "issue_1567"
 version = "0.1.0"
 dependencies = [
- "byteorder 1.4.3",
+ "byteorder 1.5.0",
 ]
 
 [[package]]
@@ -77,66 +87,44 @@ version = "0.1.0"
 name = "issue_1705"
 version = "0.1.0"
 dependencies = [
- "byteorder 1.4.3",
+ "byteorder 1.5.0",
 ]
 
 [[package]]
-name = "issue_1760"
-version = "0.1.0"
-
-[[package]]
 name = "issue_rust_86261"
 version = "0.1.0"
 
 [[package]]
-name = "proc-macro2"
-version = "1.0.66"
+name = "once_cell"
+version = "1.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
-dependencies = [
- "unicode-ident",
-]
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[package]]
-name = "quote"
-version = "1.0.33"
+name = "proc-macro2"
+version = "1.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
 dependencies = [
- "proc-macro2",
+ "unicode-ident",
 ]
 
 [[package]]
-name = "serde_derive"
-version = "1.0.185"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc59dfdcbad1437773485e0367fea4b090a2e0a16d9ffc46af47764536a298ec"
+name = "proc_macro_crate"
+version = "0.1.0"
 dependencies = [
  "proc-macro2",
- "quote",
- "syn",
 ]
 
 [[package]]
 name = "subcrate"
 version = "0.1.0"
 dependencies = [
- "byteorder 1.4.3",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.29"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
+ "byteorder 1.5.0",
 ]
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.6"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/src/tools/miri/test-cargo-miri/Cargo.toml b/src/tools/miri/test-cargo-miri/Cargo.toml
index 58c451741bb..bfef388669d 100644
--- a/src/tools/miri/test-cargo-miri/Cargo.toml
+++ b/src/tools/miri/test-cargo-miri/Cargo.toml
@@ -12,19 +12,21 @@ edition = "2018"
 byteorder = "1.0"
 cdylib = { path = "cdylib" }
 exported_symbol = { path = "exported-symbol" }
+proc_macro_crate = { path = "proc-macro-crate" }
 issue_1567 = { path = "issue-1567" }
 issue_1691 = { path = "issue-1691" }
 issue_1705 = { path = "issue-1705" }
-issue_1760 = { path = "issue-1760" }
 issue_rust_86261 = { path = "issue-rust-86261" }
 
 [dev-dependencies]
 byteorder_2 = { package = "byteorder", version = "0.5" } # to test dev-dependencies behave as expected, with renaming
-# Not actually used, but exercises some unique code path (`--extern` .so file).
-serde_derive = "1.0.185"
-# Not actually used, but uses a custom build probe so let's make sure that works.
+## More dependencies that we don't actually use, but add just for extra test coverage.
+# These use custom build probes, let's make sure they don't explode.
 # (Ideally we'd check if the probe was successful, but that's not easily possible.)
-anyhow = "1.0"
+# proc-macro2 is extra exciting because it is both a host-dependency (of proc_macro_crate above)
+# and a target-dependency.
+proc-macro2 = "1.0"
+eyre = "0.6"
 
 [build-dependencies]
 autocfg = "1"
diff --git a/src/tools/miri/test-cargo-miri/issue-1760/Cargo.toml b/src/tools/miri/test-cargo-miri/issue-1760/Cargo.toml
deleted file mode 100644
index 80925c74746..00000000000
--- a/src/tools/miri/test-cargo-miri/issue-1760/Cargo.toml
+++ /dev/null
@@ -1,8 +0,0 @@
-[package]
-name = "issue_1760"
-version = "0.1.0"
-authors = ["Miri Team"]
-edition = "2018"
-
-[lib]
-proc-macro = true
diff --git a/src/tools/miri/test-cargo-miri/proc-macro-crate/Cargo.toml b/src/tools/miri/test-cargo-miri/proc-macro-crate/Cargo.toml
new file mode 100644
index 00000000000..89652f9b042
--- /dev/null
+++ b/src/tools/miri/test-cargo-miri/proc-macro-crate/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+# regression test for issue 1760
+name = "proc_macro_crate"
+version = "0.1.0"
+authors = ["Miri Team"]
+edition = "2018"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+# A common dependency of proc macros, let's make sure that works.
+proc-macro2 = "1.0"
diff --git a/src/tools/miri/test-cargo-miri/issue-1760/build.rs b/src/tools/miri/test-cargo-miri/proc-macro-crate/build.rs
index 08427fd7164..08427fd7164 100644
--- a/src/tools/miri/test-cargo-miri/issue-1760/build.rs
+++ b/src/tools/miri/test-cargo-miri/proc-macro-crate/build.rs
diff --git a/src/tools/miri/test-cargo-miri/issue-1760/src/lib.rs b/src/tools/miri/test-cargo-miri/proc-macro-crate/src/lib.rs
index b4f6274af44..b4f6274af44 100644
--- a/src/tools/miri/test-cargo-miri/issue-1760/src/lib.rs
+++ b/src/tools/miri/test-cargo-miri/proc-macro-crate/src/lib.rs
diff --git a/src/tools/miri/test-cargo-miri/src/lib.rs b/src/tools/miri/test-cargo-miri/src/lib.rs
index e6b8c4ef65b..003341d0974 100644
--- a/src/tools/miri/test-cargo-miri/src/lib.rs
+++ b/src/tools/miri/test-cargo-miri/src/lib.rs
@@ -28,9 +28,9 @@
 /// ```
 #[no_mangle]
 pub fn make_true() -> bool {
+    proc_macro_crate::use_the_dependency!();
     issue_1567::use_the_dependency();
     issue_1705::use_the_dependency();
-    issue_1760::use_the_dependency!();
     issue_1691::use_me()
 }
 
diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_add1.rs b/src/tools/miri/tests/fail/intrinsics/unchecked_add1.rs
index 13265d0fb0e..3f8b4e55151 100644
--- a/src/tools/miri/tests/fail/intrinsics/unchecked_add1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/unchecked_add1.rs
@@ -1,5 +1,3 @@
-#![feature(unchecked_math)]
-
 fn main() {
     // MAX overflow
     let _val = unsafe { 40000u16.unchecked_add(30000) }; //~ ERROR: overflow executing `unchecked_add`
diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_add2.rs b/src/tools/miri/tests/fail/intrinsics/unchecked_add2.rs
index 229f50321d7..3283dbf8e7e 100644
--- a/src/tools/miri/tests/fail/intrinsics/unchecked_add2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/unchecked_add2.rs
@@ -1,5 +1,3 @@
-#![feature(unchecked_math)]
-
 fn main() {
     // MIN overflow
     let _val = unsafe { (-30000i16).unchecked_add(-8000) }; //~ ERROR: overflow executing `unchecked_add`
diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_mul1.rs b/src/tools/miri/tests/fail/intrinsics/unchecked_mul1.rs
index 810d3418dc8..2feed7759ec 100644
--- a/src/tools/miri/tests/fail/intrinsics/unchecked_mul1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/unchecked_mul1.rs
@@ -1,4 +1,3 @@
-#![feature(unchecked_math)]
 fn main() {
     // MAX overflow
     let _val = unsafe { 300u16.unchecked_mul(250u16) }; //~ ERROR: overflow executing `unchecked_mul`
diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_mul2.rs b/src/tools/miri/tests/fail/intrinsics/unchecked_mul2.rs
index 421019542a9..42cd509404a 100644
--- a/src/tools/miri/tests/fail/intrinsics/unchecked_mul2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/unchecked_mul2.rs
@@ -1,4 +1,3 @@
-#![feature(unchecked_math)]
 fn main() {
     // MIN overflow
     let _val = unsafe { 1_000_000_000i32.unchecked_mul(-4) }; //~ ERROR: overflow executing `unchecked_mul`
diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_sub1.rs b/src/tools/miri/tests/fail/intrinsics/unchecked_sub1.rs
index c6e00666744..e5178bf4eff 100644
--- a/src/tools/miri/tests/fail/intrinsics/unchecked_sub1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/unchecked_sub1.rs
@@ -1,4 +1,3 @@
-#![feature(unchecked_math)]
 fn main() {
     // MIN overflow
     let _val = unsafe { 14u32.unchecked_sub(22) }; //~ ERROR: overflow executing `unchecked_sub`
diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_sub2.rs b/src/tools/miri/tests/fail/intrinsics/unchecked_sub2.rs
index 65aa292e212..ac9fd1e5d06 100644
--- a/src/tools/miri/tests/fail/intrinsics/unchecked_sub2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/unchecked_sub2.rs
@@ -1,4 +1,3 @@
-#![feature(unchecked_math)]
 fn main() {
     // MAX overflow
     let _val = unsafe { 30000i16.unchecked_sub(-7000) }; //~ ERROR: overflow executing `unchecked_sub`
diff --git a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.rs b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.rs
index 20fd3306998..f89378fcb3c 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.rs
+++ b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.rs
@@ -7,6 +7,6 @@ fn main() {
 
     let x_usize: usize = x_ptr.addr();
     // Cast back an address that did *not* get exposed.
-    let ptr = std::ptr::from_exposed_addr::<i32>(x_usize);
+    let ptr = std::ptr::with_exposed_provenance::<i32>(x_usize);
     assert_eq!(unsafe { *ptr }, 3); //~ ERROR: is a dangling pointer
 }
diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
index 730859684a0..512473cd894 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
+++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
@@ -4,6 +4,6 @@
 fn main() {
     let x = 42;
     let xptr = &x as *const i32;
-    let xptr_invalid = std::ptr::without_provenance::<i32>(xptr.expose_addr());
+    let xptr_invalid = std::ptr::without_provenance::<i32>(xptr.expose_provenance());
     let _val = unsafe { *xptr_invalid }; //~ ERROR: is a dangling pointer
 }
diff --git a/src/tools/miri/tests/fail/provenance/strict_provenance_cast.rs b/src/tools/miri/tests/fail/provenance/strict_provenance_cast.rs
index 106cf4d804b..d7b54f640f6 100644
--- a/src/tools/miri/tests/fail/provenance/strict_provenance_cast.rs
+++ b/src/tools/miri/tests/fail/provenance/strict_provenance_cast.rs
@@ -3,5 +3,5 @@
 
 fn main() {
     let addr = &0 as *const i32 as usize;
-    let _ptr = std::ptr::from_exposed_addr::<i32>(addr); //~ ERROR: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported
+    let _ptr = std::ptr::with_exposed_provenance::<i32>(addr); //~ ERROR: integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported
 }
diff --git a/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr b/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr
index a110ed4ebb2..8c61b66ac46 100644
--- a/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr
+++ b/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr
@@ -1,8 +1,8 @@
-error: unsupported operation: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`
+error: unsupported operation: integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance`
   --> $DIR/strict_provenance_cast.rs:LL:CC
    |
-LL |     let _ptr = std::ptr::from_exposed_addr::<i32>(addr);
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`
+LL |     let _ptr = std::ptr::with_exposed_provenance::<i32>(addr);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance`
    |
    = help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs b/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs
index b0e4cceb98f..608ab718919 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs
+++ b/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs
@@ -6,7 +6,7 @@
 fn main() {
     let mut x = 0;
     let _fool = &mut x as *mut i32; // this would have fooled the old untagged pointer logic
-    let addr = (&x as *const i32).expose_addr();
-    let ptr = std::ptr::from_exposed_addr_mut::<i32>(addr);
+    let addr = (&x as *const i32).expose_provenance();
+    let ptr = std::ptr::with_exposed_provenance_mut::<i32>(addr);
     unsafe { *ptr = 0 }; //~ ERROR: /write access using <wildcard> .* no exposed tags have suitable permission in the borrow stack/
 }
diff --git a/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs b/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs
index 5cf62995fbe..db66b213416 100644
--- a/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs
+++ b/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs
@@ -1,6 +1,6 @@
 //@ignore-target-windows: No libc on Windows
 
-#![feature(pointer_is_aligned)]
+#![feature(pointer_is_aligned_to)]
 #![feature(strict_provenance)]
 
 use core::ptr;
diff --git a/src/tools/miri/tests/pass/async-closure-captures.rs b/src/tools/miri/tests/pass/async-closure-captures.rs
new file mode 100644
index 00000000000..3e33de32efb
--- /dev/null
+++ b/src/tools/miri/tests/pass/async-closure-captures.rs
@@ -0,0 +1,91 @@
+// Same as rustc's `tests/ui/async-await/async-closures/captures.rs`, keep in sync
+
+#![feature(async_closure, noop_waker)]
+
+use std::future::Future;
+use std::pin::pin;
+use std::task::*;
+
+pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
+    let mut fut = pin!(fut);
+    let ctx = &mut Context::from_waker(Waker::noop());
+
+    loop {
+        match fut.as_mut().poll(ctx) {
+            Poll::Pending => {}
+            Poll::Ready(t) => break t,
+        }
+    }
+}
+
+fn main() {
+    block_on(async_main());
+}
+
+async fn call<T>(f: &impl async Fn() -> T) -> T {
+    f().await
+}
+
+async fn call_once<T>(f: impl async FnOnce() -> T) -> T {
+    f().await
+}
+
+#[derive(Debug)]
+#[allow(unused)]
+struct Hello(i32);
+
+async fn async_main() {
+    // Capture something by-ref
+    {
+        let x = Hello(0);
+        let c = async || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+
+        let x = &Hello(1);
+        let c = async || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+    }
+
+    // Capture something and consume it (force to `AsyncFnOnce`)
+    {
+        let x = Hello(2);
+        let c = async || {
+            println!("{x:?}");
+            drop(x);
+        };
+        call_once(c).await;
+    }
+
+    // Capture something with `move`, don't consume it
+    {
+        let x = Hello(3);
+        let c = async move || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+
+        let x = &Hello(4);
+        let c = async move || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+    }
+
+    // Capture something with `move`, also consume it (so `AsyncFnOnce`)
+    {
+        let x = Hello(5);
+        let c = async move || {
+            println!("{x:?}");
+            drop(x);
+        };
+        call_once(c).await;
+    }
+}
diff --git a/src/tools/miri/tests/pass/async-closure-captures.stdout b/src/tools/miri/tests/pass/async-closure-captures.stdout
new file mode 100644
index 00000000000..a0db6d236fe
--- /dev/null
+++ b/src/tools/miri/tests/pass/async-closure-captures.stdout
@@ -0,0 +1,10 @@
+Hello(0)
+Hello(0)
+Hello(1)
+Hello(1)
+Hello(2)
+Hello(3)
+Hello(3)
+Hello(4)
+Hello(4)
+Hello(5)
diff --git a/src/tools/miri/tests/pass/box.stack.stderr b/src/tools/miri/tests/pass/box.stack.stderr
index f6e208cea9a..1a4d52ee314 100644
--- a/src/tools/miri/tests/pass/box.stack.stderr
+++ b/src/tools/miri/tests/pass/box.stack.stderr
@@ -4,11 +4,11 @@ warning: integer-to-pointer cast
 LL |         let r2 = ((r as usize) + 0) as *mut i32;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
    |
-   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,
+   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
    = help: which means that Miri might miss pointer bugs in this program.
-   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation.
+   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
    = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
-   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics.
+   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
    = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
    = note: BACKTRACE:
    = note: inside `into_raw` at $DIR/box.rs:LL:CC
diff --git a/src/tools/miri/tests/pass/extern_types.stack.stderr b/src/tools/miri/tests/pass/extern_types.stack.stderr
index 2e18f693058..275d718129b 100644
--- a/src/tools/miri/tests/pass/extern_types.stack.stderr
+++ b/src/tools/miri/tests/pass/extern_types.stack.stderr
@@ -4,11 +4,11 @@ warning: integer-to-pointer cast
 LL |     let x: &Foo = unsafe { &*(16 as *const Foo) };
    |                              ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
    |
-   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,
+   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
    = help: which means that Miri might miss pointer bugs in this program.
-   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation.
+   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
    = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
-   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics.
+   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
    = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
    = note: BACKTRACE:
    = note: inside `main` at $DIR/extern_types.rs:LL:CC
diff --git a/src/tools/miri/tests/pass/portable-simd-ptrs.rs b/src/tools/miri/tests/pass/portable-simd-ptrs.rs
index 70ba5636c60..096ec78da1a 100644
--- a/src/tools/miri/tests/pass/portable-simd-ptrs.rs
+++ b/src/tools/miri/tests/pass/portable-simd-ptrs.rs
@@ -7,6 +7,6 @@ use std::simd::prelude::*;
 fn main() {
     // Pointer casts
     let _val: Simd<*const u8, 4> = Simd::<*const i32, 4>::splat(ptr::null()).cast();
-    let addrs = Simd::<*const i32, 4>::splat(ptr::null()).expose_addr();
-    let _ptrs = Simd::<*const i32, 4>::from_exposed_addr(addrs);
+    let addrs = Simd::<*const i32, 4>::splat(ptr::null()).expose_provenance();
+    let _ptrs = Simd::<*const i32, 4>::with_exposed_provenance(addrs);
 }
diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
index d8d57679e6b..5690d7865bb 100644
--- a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
+++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
@@ -10,9 +10,9 @@ fn ptr_roundtrip_out_of_bounds() {
     let x: i32 = 3;
     let x_ptr = &x as *const i32;
 
-    let x_usize = x_ptr.wrapping_offset(128).expose_addr();
+    let x_usize = x_ptr.wrapping_offset(128).expose_provenance();
 
-    let ptr = ptr::from_exposed_addr::<i32>(x_usize).wrapping_offset(-128);
+    let ptr = ptr::with_exposed_provenance::<i32>(x_usize).wrapping_offset(-128);
     assert_eq!(unsafe { *ptr }, 3);
 }
 
@@ -24,10 +24,10 @@ fn ptr_roundtrip_confusion() {
     let x_ptr = &x as *const i32;
     let y_ptr = &y as *const i32;
 
-    let x_usize = x_ptr.expose_addr();
-    let y_usize = y_ptr.expose_addr();
+    let x_usize = x_ptr.expose_provenance();
+    let y_usize = y_ptr.expose_provenance();
 
-    let ptr = ptr::from_exposed_addr::<i32>(y_usize);
+    let ptr = ptr::with_exposed_provenance::<i32>(y_usize);
     let ptr = ptr.with_addr(x_usize);
     assert_eq!(unsafe { *ptr }, 0);
 }
@@ -37,9 +37,9 @@ fn ptr_roundtrip_imperfect() {
     let x: u8 = 3;
     let x_ptr = &x as *const u8;
 
-    let x_usize = x_ptr.expose_addr() + 128;
+    let x_usize = x_ptr.expose_provenance() + 128;
 
-    let ptr = ptr::from_exposed_addr::<u8>(x_usize).wrapping_offset(-128);
+    let ptr = ptr::with_exposed_provenance::<u8>(x_usize).wrapping_offset(-128);
     assert_eq!(unsafe { *ptr }, 3);
 }
 
@@ -48,10 +48,10 @@ fn ptr_roundtrip_null() {
     let x = &42;
     let x_ptr = x as *const i32;
     let x_null_ptr = x_ptr.with_addr(0); // addr 0, but still the provenance of x
-    let null = x_null_ptr.expose_addr();
+    let null = x_null_ptr.expose_provenance();
     assert_eq!(null, 0);
 
-    let x_null_ptr_copy = ptr::from_exposed_addr::<i32>(null); // just a roundtrip, so has provenance of x (angelically)
+    let x_null_ptr_copy = ptr::with_exposed_provenance::<i32>(null); // just a roundtrip, so has provenance of x (angelically)
     let x_ptr_copy = x_null_ptr_copy.with_addr(x_ptr.addr()); // addr of x and provenance of x
     assert_eq!(unsafe { *x_ptr_copy }, 42);
 }
diff --git a/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs b/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs
index e467356dd04..c89d79b42e3 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs
@@ -17,7 +17,7 @@ fn example(variant: bool) {
     unsafe {
         fn not_so_innocent(x: &mut u32) -> usize {
             let x_raw4 = x as *mut u32;
-            x_raw4.expose_addr()
+            x_raw4.expose_provenance()
         }
 
         let mut c = 42u32;
@@ -26,7 +26,7 @@ fn example(variant: bool) {
         // stack: [..., Unique(1)]
 
         let x_raw2 = x_unique1 as *mut u32;
-        let x_raw2_addr = x_raw2.expose_addr();
+        let x_raw2_addr = x_raw2.expose_provenance();
         // stack: [..., Unique(1), SharedRW(2)]
 
         let x_unique3 = &mut *x_raw2;
@@ -39,7 +39,7 @@ fn example(variant: bool) {
         // 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers).
         // And indeed if `variant == true` it is the only possible choice.
         // But if `variant == false` then 2 is the only possible choice!
-        let x_wildcard = ptr::from_exposed_addr_mut::<i32>(x_raw2_addr);
+        let x_wildcard = ptr::with_exposed_provenance_mut::<i32>(x_raw2_addr);
 
         if variant {
             // If we picked 2, this will invalidate 3.
diff --git a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr b/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr
index f3ba052ae51..7cbfad3942b 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr
+++ b/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr
@@ -4,11 +4,11 @@ warning: integer-to-pointer cast
 LL |         let wildcard = &root0 as *const Cell<i32> as usize as *const Cell<i32>;
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
    |
-   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,
+   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
    = help: which means that Miri might miss pointer bugs in this program.
-   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation.
+   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
    = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
-   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics.
+   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
    = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
    = note: BACKTRACE:
    = note: inside `main` at $DIR/issue-miri-2389.rs:LL:CC
diff --git a/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs b/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs
index 5bb4e879c3e..55356814a1a 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs
@@ -9,7 +9,7 @@ fn main() {
 
     // Expose the allocation and use the exposed pointer, creating an unknown bottom
     unsafe {
-        let p: *mut u8 = ptr::from_exposed_addr::<u8>(ptr.expose_addr()) as *mut u8;
+        let p: *mut u8 = ptr::with_exposed_provenance::<u8>(ptr.expose_provenance()) as *mut u8;
         *p = 1;
     }
 
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index 129d1dfd732..a75fa4cf986 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -54,34 +54,13 @@ fn build_so_for_c_ffi_tests() -> PathBuf {
     so_file_path
 }
 
-fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> Config {
+/// Does *not* set any args or env vars, since it is shared between the test runner and
+/// run_dep_mode.
+fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> Config {
     // Miri is rustc-like, so we create a default builder for rustc and modify it
     let mut program = CommandBuilder::rustc();
     program.program = miri_path();
 
-    // Add some flags we always want.
-    program.args.push("-Dwarnings".into());
-    program.args.push("-Dunused".into());
-    program.args.push("-Ainternal_features".into());
-    if let Ok(extra_flags) = env::var("MIRIFLAGS") {
-        for flag in extra_flags.split_whitespace() {
-            program.args.push(flag.into());
-        }
-    }
-    program.args.push("-Zui-testing".into());
-    program.args.push("--target".into());
-    program.args.push(target.into());
-
-    // If we're on linux, and we're testing the extern-so functionality,
-    // then build the shared object file for testing external C function calls
-    // and push the relevant compiler flag.
-    if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") {
-        let so_file_path = build_so_for_c_ffi_tests();
-        let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
-        flag.push(so_file_path.into_os_string());
-        program.args.push(flag);
-    }
-
     let mut config = Config {
         target: Some(target.to_owned()),
         stderr_filters: STDERR.clone(),
@@ -119,17 +98,38 @@ fn run_tests(
     with_dependencies: bool,
     tmpdir: &Path,
 ) -> Result<()> {
-    let mut config = test_config(target, path, mode, with_dependencies);
+    let mut config = miri_config(target, path, mode, with_dependencies);
 
     // Add a test env var to do environment communication tests.
     config.program.envs.push(("MIRI_ENV_VAR_TEST".into(), Some("0".into())));
-
     // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
     config.program.envs.push(("MIRI_TEMP".into(), Some(tmpdir.to_owned().into())));
-
     // If a test ICEs, we want to see a backtrace.
     config.program.envs.push(("RUST_BACKTRACE".into(), Some("1".into())));
 
+    // Add some flags we always want.
+    config.program.args.push("-Dwarnings".into());
+    config.program.args.push("-Dunused".into());
+    config.program.args.push("-Ainternal_features".into());
+    if let Ok(extra_flags) = env::var("MIRIFLAGS") {
+        for flag in extra_flags.split_whitespace() {
+            config.program.args.push(flag.into());
+        }
+    }
+    config.program.args.push("-Zui-testing".into());
+    config.program.args.push("--target".into());
+    config.program.args.push(target.into());
+
+    // If we're on linux, and we're testing the extern-so functionality,
+    // then build the shared object file for testing external C function calls
+    // and push the relevant compiler flag.
+    if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") {
+        let so_file_path = build_so_for_c_ffi_tests();
+        let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
+        flag.push(so_file_path.into_os_string());
+        config.program.args.push(flag);
+    }
+
     // Handle command-line arguments.
     let args = ui_test::Args::test()?;
     let default_bless = env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
@@ -292,13 +292,12 @@ fn main() -> Result<()> {
 
 fn run_dep_mode(target: String, mut args: impl Iterator<Item = OsString>) -> Result<()> {
     let path = args.next().expect("./miri run-dep must be followed by a file name");
-    let mut config = test_config(
+    let config = miri_config(
         &target,
         "",
         Mode::Yolo { rustfix: RustfixMode::Disabled },
         /* with dependencies */ true,
     );
-    config.program.args.clear(); // We want to give the user full control over flags
     let dep_args = config.build_dependencies()?;
 
     let mut cmd = config.program.build(&config.out_dir);
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 7975677286d..48fa2bbf1ac 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -19,7 +19,11 @@ pub fn tmp_dir() -> PathBuf {
 }
 
 fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! {
-    eprintln!("command failed at line {caller_line_number}");
+    if output.status.success() {
+        eprintln!("command incorrectly succeeded at line {caller_line_number}");
+    } else {
+        eprintln!("command failed at line {caller_line_number}");
+    }
     eprintln!("{cmd}");
     eprintln!("output status: `{}`", output.status);
     eprintln!("=== STDOUT ===\n{}\n\n", String::from_utf8(output.stdout).unwrap());
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index d0ab8df42d2..50ff0d26bbb 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -1,4 +1,5 @@
 use std::env;
+use std::ffi::OsStr;
 use std::path::Path;
 use std::process::{Command, Output};
 
@@ -104,6 +105,20 @@ impl Rustc {
         self
     }
 
+    /// Specify the crate type.
+    pub fn crate_type(&mut self, crate_type: &str) -> &mut Self {
+        self.cmd.arg("--crate-type");
+        self.cmd.arg(crate_type);
+        self
+    }
+
+    /// Specify the edition year.
+    pub fn edition(&mut self, edition: &str) -> &mut Self {
+        self.cmd.arg("--edition");
+        self.cmd.arg(edition);
+        self
+    }
+
     /// Generic command arguments provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
     /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z <name>` or `-C <name>`
     /// is passed (note the space).
@@ -119,6 +134,11 @@ impl Rustc {
         self
     }
 
+    pub fn env(&mut self, name: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Self {
+        self.cmd.env(name, value);
+        self
+    }
+
     // Command inspection, output and running helper methods
 
     /// Get the [`Output`][std::process::Output] of the finished `rustc` process.
@@ -139,6 +159,18 @@ impl Rustc {
         output
     }
 
+    #[track_caller]
+    pub fn run_fail(&mut self) -> Output {
+        let caller_location = std::panic::Location::caller();
+        let caller_line_number = caller_location.line();
+
+        let output = self.cmd.output().unwrap();
+        if output.status.success() {
+            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
+        }
+        output
+    }
+
     /// Inspect what the underlying [`Command`] is up to the current construction.
     pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self {
         f(&self.cmd);
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 2d8946520d5..08ad10c2971 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -71,7 +71,7 @@ jobs:
         run: echo "::add-matcher::.github/rust.json"
 
       - name: Cache Dependencies
-        uses: Swatinem/rust-cache@988c164c3d0e93c4dbab36aaf5bbeb77425b2894
+        uses: Swatinem/rust-cache@640a22190e7a783d4c409684cea558f081f92012
         with:
           key: ${{ env.RUST_CHANNEL }}
 
@@ -140,7 +140,7 @@ jobs:
           rustup target add ${{ env.targets }} ${{ env.targets_ide }}
 
       - name: Cache Dependencies
-        uses: Swatinem/rust-cache@988c164c3d0e93c4dbab36aaf5bbeb77425b2894
+        uses: Swatinem/rust-cache@640a22190e7a783d4c409684cea558f081f92012
 
       - name: Check
         run: |
diff --git a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
index 862373ec1cc..34ca53e2e53 100644
--- a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
@@ -32,4 +32,5 @@ jobs:
           git config --global user.name "GitHub Action"
           # Remove r-a crates from the workspaces so we don't auto-publish them as well
           sed -i 's/ "crates\/\*"//' ./Cargo.toml
+          sed -i 's/ "xtask\/"//' ./Cargo.toml
           cargo workspaces publish --yes --exact --from-git --no-git-commit --allow-dirty
diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml
index dc0a6c2d91f..11014338d72 100644
--- a/src/tools/rust-analyzer/.github/workflows/release.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/release.yaml
@@ -36,6 +36,7 @@ jobs:
           - os: ubuntu-20.04
             target: x86_64-unknown-linux-gnu
             code-target: linux-x64
+            container: rockylinux:8
           - os: ubuntu-20.04
             target: aarch64-unknown-linux-gnu
             code-target: linux-arm64
@@ -58,10 +59,18 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: ${{ env.FETCH_DEPTH }}
 
+      - name: Install toolchain dependencies
+        if: matrix.container == 'rockylinux:8'
+        shell: bash
+        run: |
+          dnf install -y gcc
+          curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --profile minimal --default-toolchain none -y
+          echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH
+
       - name: Install Rust toolchain
         run: |
           rustup update --no-self-update stable
@@ -69,9 +78,9 @@ jobs:
           rustup component add rust-src
 
       - name: Install Node.js
-        uses: actions/setup-node@v3
+        uses: actions/setup-node@v4
         with:
-          node-version: 16
+          node-version: 18
 
       - name: Update apt repositories
         if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
@@ -181,7 +190,7 @@ jobs:
       - name: Install Nodejs
         uses: actions/setup-node@v4
         with:
-          node-version: 18
+          node-version: 20
 
       - run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV
         if: github.ref == 'refs/heads/release'
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 68ed32391b7..c7cf4479b33 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -594,6 +594,7 @@ dependencies = [
  "rustc-hash",
  "scoped-tls",
  "smallvec",
+ "span",
  "stdx",
  "syntax",
  "test-fixture",
@@ -637,6 +638,7 @@ dependencies = [
  "pulldown-cmark",
  "pulldown-cmark-to-cmark",
  "smallvec",
+ "span",
  "stdx",
  "syntax",
  "test-fixture",
@@ -732,6 +734,7 @@ dependencies = [
  "ide-db",
  "itertools",
  "once_cell",
+ "paths",
  "serde_json",
  "stdx",
  "syntax",
@@ -931,6 +934,7 @@ dependencies = [
  "hir-expand",
  "ide-db",
  "itertools",
+ "paths",
  "proc-macro-api",
  "project-model",
  "span",
@@ -1225,6 +1229,9 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
 [[package]]
 name = "paths"
 version = "0.0.0"
+dependencies = [
+ "camino",
+]
 
 [[package]]
 name = "percent-encoding"
@@ -1375,6 +1382,7 @@ dependencies = [
  "semver",
  "serde",
  "serde_json",
+ "span",
  "stdx",
  "toolchain",
  "tracing",
@@ -1432,9 +1440,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.42.0"
+version = "0.44.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2ae52e2d5b08762c9464b541345f519b8719d57b643b73632bade43ecece9dc"
+checksum = "b8709df2a746f055316bc0c62bd30948695a25e734863bf6e1f9755403e010ab"
 dependencies = [
  "bitflags 2.4.2",
  "ra-ap-rustc_index",
@@ -1443,9 +1451,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.42.0"
+version = "0.44.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfd7e10c7853fe79443d46e1d2d8ab09fe99926118e59653fb8b480d5045f126"
+checksum = "9ad68bacffb87dcdbb23a3ce11261375078aaa06b85d348c49f39ffd5510dc20"
 dependencies = [
  "arrayvec",
  "ra-ap-rustc_index_macros",
@@ -1454,9 +1462,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.42.0"
+version = "0.44.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47f1d1c589be6c9a9e852fadee0e60329c0f862e87442ac2fe5adae30663cc76"
+checksum = "8782aaf3a113837c533dfb1c45df91cd17e1fdd1d2f9a20c2e0d1976025c4f1f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1466,9 +1474,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.42.0"
+version = "0.44.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa852373a757b4c723bbdc96ced7f575cad68a1e266e45fee12bc4c69a482d80"
+checksum = "aab683fc8579d09eb72033bd5dc9ba6d701aa9645b5fed087ef19af71184dff3"
 dependencies = [
  "unicode-properties",
  "unicode-xid",
@@ -1476,9 +1484,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.42.0"
+version = "0.44.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2afe3c49accd95a53ac4d72ae13bafc7d115bdd80c8cd56ab09e6fc68f482210"
+checksum = "0bcf9ff5edbf784b67b8ad5e03a068f1300fcc24062c0d476b3018965135d933"
 dependencies = [
  "ra-ap-rustc_index",
  "ra-ap-rustc_lexer",
@@ -1486,9 +1494,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.42.0"
+version = "0.44.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1253da23515d80c377a3998731e0ec3794997b62b989fd47db73efbde6a0bd7c"
+checksum = "d63d1e1d5b2a13273cee1a10011147418f40e12b70f70578ce1dee0f1cafc334"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash",
@@ -1598,6 +1606,7 @@ dependencies = [
  "oorandom",
  "parking_lot",
  "parser",
+ "paths",
  "proc-macro-api",
  "profile",
  "project-model",
@@ -1869,20 +1878,16 @@ dependencies = [
  "itertools",
  "once_cell",
  "parser",
- "proc-macro2",
- "quote",
  "ra-ap-rustc_lexer",
  "rayon",
  "rowan",
  "rustc-hash",
  "smol_str",
- "sourcegen",
  "stdx",
  "test-utils",
  "text-edit",
  "tracing",
  "triomphe",
- "ungrammar",
 ]
 
 [[package]]
@@ -2024,6 +2029,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 name = "toolchain"
 version = "0.0.0"
 dependencies = [
+ "camino",
  "home",
 ]
 
@@ -2109,7 +2115,6 @@ name = "tt"
 version = "0.0.0"
 dependencies = [
  "smol_str",
- "span",
  "stdx",
  "text-size",
 ]
@@ -2438,8 +2443,12 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "flate2",
+ "itertools",
+ "proc-macro2",
+ "quote",
  "stdx",
  "time",
+ "ungrammar",
  "write-json",
  "xflags",
  "xshell",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 0679522efd6..d9343d2b963 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -84,11 +84,11 @@ tt = { path = "./crates/tt", version = "0.0.0" }
 vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
 vfs = { path = "./crates/vfs", version = "0.0.0" }
 
-ra-ap-rustc_lexer = { version = "0.42.0", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.42.0", default-features = false }
-ra-ap-rustc_index = { version = "0.42.0", default-features = false }
-ra-ap-rustc_abi = { version = "0.42.0", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.42.0", default-features = false }
+ra-ap-rustc_lexer = { version = "0.44.0", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.44.0", default-features = false }
+ra-ap-rustc_index = { version = "0.44.0", default-features = false }
+ra-ap-rustc_abi = { version = "0.44.0", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.44.0", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 sourcegen = { path = "./crates/sourcegen" }
@@ -105,6 +105,7 @@ anyhow = "1.0.75"
 arrayvec = "0.7.4"
 bitflags = "2.4.1"
 cargo_metadata = "0.18.1"
+camino = "1.1.6"
 chalk-solve = { version = "0.96.0", default-features = false }
 chalk-ir = "0.96.0"
 chalk-recursive = { version = "0.96.0", default-features = false }
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index b243b37b77b..27eb05cd4dc 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -6,11 +6,12 @@
 //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how
 //! actual IO is done and lowered to input.
 
-use std::{fmt, mem, ops, str::FromStr};
+use std::{fmt, mem, ops};
 
 use cfg::CfgOptions;
 use la_arena::{Arena, Idx, RawIdx};
 use rustc_hash::{FxHashMap, FxHashSet};
+use span::Edition;
 use syntax::SmolStr;
 use triomphe::Arc;
 use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath};
@@ -293,42 +294,11 @@ pub struct CrateData {
     pub is_proc_macro: bool,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum Edition {
-    Edition2015,
-    Edition2018,
-    Edition2021,
-    Edition2024,
-}
-
-impl Edition {
-    pub const CURRENT: Edition = Edition::Edition2021;
-    pub const DEFAULT: Edition = Edition::Edition2015;
-}
-
 #[derive(Default, Debug, Clone, PartialEq, Eq)]
 pub struct Env {
     entries: FxHashMap<String, String>,
 }
 
-impl Env {
-    pub fn new_for_test_fixture() -> Self {
-        Env {
-            entries: FxHashMap::from_iter([(
-                String::from("__ra_is_test_fixture"),
-                String::from("__ra_is_test_fixture"),
-            )]),
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub enum DependencyKind {
-    Normal,
-    Dev,
-    Build,
-}
-
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Dependency {
     pub crate_id: CrateId,
@@ -530,13 +500,6 @@ impl CrateGraph {
         }
     }
 
-    // FIXME: this only finds one crate with the given root; we could have multiple
-    pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
-        let (crate_id, _) =
-            self.arena.iter().find(|(_crate_id, data)| data.root_file_id == file_id)?;
-        Some(crate_id)
-    }
-
     pub fn sort_deps(&mut self) {
         self.arena
             .iter_mut()
@@ -653,6 +616,10 @@ impl CrateGraph {
         }
         id_map
     }
+
+    pub fn shrink_to_fit(&mut self) {
+        self.arena.shrink_to_fit();
+    }
 }
 
 impl ops::Index<CrateId> for CrateGraph {
@@ -670,32 +637,6 @@ impl CrateData {
     }
 }
 
-impl FromStr for Edition {
-    type Err = ParseEditionError;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let res = match s {
-            "2015" => Edition::Edition2015,
-            "2018" => Edition::Edition2018,
-            "2021" => Edition::Edition2021,
-            "2024" => Edition::Edition2024,
-            _ => return Err(ParseEditionError { invalid_input: s.to_owned() }),
-        };
-        Ok(res)
-    }
-}
-
-impl fmt::Display for Edition {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(match self {
-            Edition::Edition2015 => "2015",
-            Edition::Edition2018 => "2018",
-            Edition::Edition2021 => "2021",
-            Edition::Edition2024 => "2024",
-        })
-    }
-}
-
 impl Extend<(String, String)> for Env {
     fn extend<T: IntoIterator<Item = (String, String)>>(&mut self, iter: T) {
         self.entries.extend(iter);
@@ -723,19 +664,6 @@ impl Env {
 }
 
 #[derive(Debug)]
-pub struct ParseEditionError {
-    invalid_input: String,
-}
-
-impl fmt::Display for ParseEditionError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "invalid edition: {:?}", self.invalid_input)
-    }
-}
-
-impl std::error::Error for ParseEditionError {}
-
-#[derive(Debug)]
 pub struct CyclicDependenciesError {
     path: Vec<(CrateId, Option<CrateDisplayName>)>,
 }
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index 5dcb580723f..785ff9ceffa 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -14,9 +14,9 @@ use triomphe::Arc;
 pub use crate::{
     change::FileChange,
     input::{
-        CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency,
-        DependencyKind, Edition, Env, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, SourceRoot,
-        SourceRootId, TargetLayoutLoadResult,
+        CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env,
+        LangCrateOrigin, ProcMacroPaths, ReleaseChannel, SourceRoot, SourceRootId,
+        TargetLayoutLoadResult,
     },
 };
 pub use salsa::{self, Cancelled};
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
index f8efb520222..4ee86954acd 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
@@ -8,10 +8,10 @@
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-use std::{fmt, io, path::PathBuf, process::Command, time::Duration};
+use std::{fmt, io, process::Command, time::Duration};
 
 use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
-use paths::{AbsPath, AbsPathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
 use rustc_hash::FxHashMap;
 use serde::Deserialize;
 
@@ -53,7 +53,7 @@ pub enum FlycheckConfig {
         extra_args: Vec<String>,
         extra_env: FxHashMap<String, String>,
         ansi_color_output: bool,
-        target_dir: Option<PathBuf>,
+        target_dir: Option<Utf8PathBuf>,
     },
     CustomCommand {
         command: String,
@@ -363,7 +363,7 @@ impl FlycheckActor {
                 });
 
                 cmd.arg("--manifest-path");
-                cmd.arg(self.root.join("Cargo.toml").as_os_str());
+                cmd.arg(self.root.join("Cargo.toml"));
 
                 for target in target_triples {
                     cmd.args(["--target", target.as_str()]);
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs b/src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs
index 31378716b3e..9f761c9ead1 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs
@@ -55,13 +55,16 @@ pub struct CargoTestHandle {
 }
 
 // Example of a cargo test command:
-// cargo test -- module::func -Z unstable-options --format=json
+// cargo test --workspace --no-fail-fast -- module::func -Z unstable-options --format=json
 
 impl CargoTestHandle {
     pub fn new(path: Option<&str>) -> std::io::Result<Self> {
         let mut cmd = Command::new(Tool::Cargo.path());
         cmd.env("RUSTC_BOOTSTRAP", "1");
         cmd.arg("test");
+        cmd.arg("--workspace");
+        // --no-fail-fast is needed to ensure that all requested tests will run
+        cmd.arg("--no-fail-fast");
         cmd.arg("--");
         if let Some(path) = path {
             cmd.arg(path);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index 21536098b82..fa7730f302e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -148,12 +148,12 @@ impl Attrs {
         }
     }
 
-    pub fn lang(&self) -> Option<&SmolStr> {
+    pub fn lang(&self) -> Option<&str> {
         self.by_key("lang").string_value()
     }
 
     pub fn lang_item(&self) -> Option<LangItem> {
-        self.by_key("lang").string_value().and_then(|it| LangItem::from_str(it))
+        self.by_key("lang").string_value().and_then(LangItem::from_str)
     }
 
     pub fn has_doc_hidden(&self) -> bool {
@@ -178,7 +178,7 @@ impl Attrs {
         self.doc_exprs().flat_map(|doc_expr| doc_expr.aliases().to_vec())
     }
 
-    pub fn export_name(&self) -> Option<&SmolStr> {
+    pub fn export_name(&self) -> Option<&str> {
         self.by_key("export_name").string_value()
     }
 
@@ -565,7 +565,7 @@ impl<'attr> AttrQuery<'attr> {
         self.attrs().filter_map(|attr| attr.token_tree_value())
     }
 
-    pub fn string_value(self) -> Option<&'attr SmolStr> {
+    pub fn string_value(self) -> Option<&'attr str> {
         self.attrs().find_map(|attr| attr.string_value())
     }
 
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 b815c9b73ef..da790f11516 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -453,8 +453,8 @@ impl ProcMacroData {
             (
                 def.name,
                 match def.kind {
-                    ProcMacroKind::CustomDerive { helpers } => Some(helpers),
-                    ProcMacroKind::FnLike | ProcMacroKind::Attr => None,
+                    ProcMacroKind::Derive { helpers } => Some(helpers),
+                    ProcMacroKind::Bang | ProcMacroKind::Attr => None,
                 },
             )
         } else {
@@ -484,10 +484,11 @@ impl ExternCrateDeclData {
         let extern_crate = &item_tree[loc.id.value];
 
         let name = extern_crate.name.clone();
+        let krate = loc.container.krate();
         let crate_id = if name == hir_expand::name![self] {
-            Some(loc.container.krate())
+            Some(krate)
         } else {
-            db.crate_def_map(loc.container.krate())
+            db.crate_def_map(krate)
                 .extern_prelude()
                 .find(|&(prelude_name, ..)| *prelude_name == name)
                 .map(|(_, (root, _))| root.krate())
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index 1d2c7c3a55f..4638b377197 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -22,8 +22,8 @@ use crate::{
     lower::LowerCtx,
     nameres::{DefMap, MacroSubNs},
     type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
-    AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LocalTypeOrConstParamId, Lookup,
-    TypeOrConstParamId, TypeParamId,
+    AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
+    LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
 };
 
 /// Data about a generic type parameter (to a function, struct, impl, ...).
@@ -102,6 +102,52 @@ impl TypeOrConstParamData {
 
 impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
 
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum GenericParamData {
+    TypeParamData(TypeParamData),
+    ConstParamData(ConstParamData),
+    LifetimeParamData(LifetimeParamData),
+}
+
+impl GenericParamData {
+    pub fn name(&self) -> Option<&Name> {
+        match self {
+            GenericParamData::TypeParamData(it) => it.name.as_ref(),
+            GenericParamData::ConstParamData(it) => Some(&it.name),
+            GenericParamData::LifetimeParamData(it) => Some(&it.name),
+        }
+    }
+
+    pub fn type_param(&self) -> Option<&TypeParamData> {
+        match self {
+            GenericParamData::TypeParamData(it) => Some(it),
+            _ => None,
+        }
+    }
+
+    pub fn const_param(&self) -> Option<&ConstParamData> {
+        match self {
+            GenericParamData::ConstParamData(it) => Some(it),
+            _ => None,
+        }
+    }
+
+    pub fn lifetime_param(&self) -> Option<&LifetimeParamData> {
+        match self {
+            GenericParamData::LifetimeParamData(it) => Some(it),
+            _ => None,
+        }
+    }
+}
+
+impl_from!(TypeParamData, ConstParamData, LifetimeParamData for GenericParamData);
+
+pub enum GenericParamDataRef<'a> {
+    TypeParamData(&'a TypeParamData),
+    ConstParamData(&'a ConstParamData),
+    LifetimeParamData(&'a LifetimeParamData),
+}
+
 /// Data about the generic parameters of a function, struct, impl, etc.
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct GenericParams {
@@ -358,6 +404,15 @@ impl GenericParamsCollector {
 }
 
 impl GenericParams {
+    /// Number of Generic parameters (type_or_consts + lifetimes)
+    pub fn len(&self) -> usize {
+        self.type_or_consts.len() + self.lifetimes.len()
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
     /// Iterator of type_or_consts field
     pub fn iter(
         &self,
@@ -365,6 +420,13 @@ impl GenericParams {
         self.type_or_consts.iter()
     }
 
+    /// Iterator of lifetimes field
+    pub fn iter_lt(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = (Idx<LifetimeParamData>, &LifetimeParamData)> {
+        self.lifetimes.iter()
+    }
+
     pub(crate) fn generic_params_query(
         db: &dyn DefDatabase,
         def: GenericDefId,
@@ -507,4 +569,18 @@ impl GenericParams {
             .then(|| id)
         })
     }
+
+    pub fn find_lifetime_by_name(
+        &self,
+        name: &Name,
+        parent: GenericDefId,
+    ) -> Option<LifetimeParamId> {
+        self.lifetimes.iter().find_map(|(id, p)| {
+            if &p.name == name {
+                Some(LifetimeParamId { local_id: id, parent })
+            } else {
+                None
+            }
+        })
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 953bf6b85d6..0c84057950b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -526,7 +526,7 @@ impl Printer<'_> {
     }
 
     fn print_generic_params(&mut self, params: &GenericParams) {
-        if params.type_or_consts.is_empty() && params.lifetimes.is_empty() {
+        if params.is_empty() {
             return;
         }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
index 7d98f6cfe88..3a07c678428 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
@@ -192,7 +192,7 @@ impl LangItems {
 
 pub(crate) fn lang_attr(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangItem> {
     let attrs = db.attrs(item);
-    attrs.by_key("lang").string_value().and_then(|it| LangItem::from_str(it))
+    attrs.by_key("lang").string_value().and_then(LangItem::from_str)
 }
 
 pub(crate) fn notable_traits_in_deps(
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 828842de7e8..46898ce542d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -73,7 +73,7 @@ use std::{
 use base_db::{
     impl_intern_key,
     salsa::{self, impl_intern_value_trivial},
-    CrateId, Edition,
+    CrateId,
 };
 use hir_expand::{
     builtin_attr_macro::BuiltinAttrExpander,
@@ -90,7 +90,7 @@ use hir_expand::{
 use item_tree::ExternBlock;
 use la_arena::Idx;
 use nameres::DefMap;
-use span::{AstIdNode, FileAstId, FileId, SyntaxContextId};
+use span::{AstIdNode, Edition, FileAstId, FileId, SyntaxContextId};
 use stdx::impl_from;
 use syntax::{ast, AstNode};
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index 965f329acb9..c5c26e26bc0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -1449,6 +1449,7 @@ ok!();
 #[test]
 fn test_new_std_matches() {
     check(
+        //- edition:2021
         r#"
 macro_rules! matches {
     ($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => {
@@ -1481,6 +1482,90 @@ fn main() {
 }
 
 #[test]
+fn test_hygienic_pat() {
+    check(
+        r#"
+//- /new.rs crate:new deps:old edition:2015
+old::make!();
+fn main() {
+    matches!(0, 0 | 1 if true);
+}
+//- /old.rs crate:old edition:2021
+#[macro_export]
+macro_rules! make {
+    () => {
+        macro_rules! matches {
+            ($expression:expr, $pattern:pat if $guard:expr ) => {
+                match $expression {
+                    $pattern if $guard => true,
+                    _ => false
+                }
+            };
+        }
+    }
+}
+ "#,
+        expect![[r#"
+macro_rules !matches {
+    ($expression: expr, $pattern: pat if $guard: expr) = > {
+        match $expression {
+            $pattern if $guard = > true , _ = > false
+        }
+    }
+    ;
+}
+fn main() {
+    match 0 {
+        0|1 if true =>true , _=>false
+    };
+}
+"#]],
+    );
+    check(
+        r#"
+//- /new.rs crate:new deps:old edition:2021
+old::make!();
+fn main() {
+    matches/*+errors*/!(0, 0 | 1 if true);
+}
+//- /old.rs crate:old edition:2015
+#[macro_export]
+macro_rules! make {
+    () => {
+        macro_rules! matches {
+            ($expression:expr, $pattern:pat if $guard:expr ) => {
+                match $expression {
+                    $pattern if $guard => true,
+                    _ => false
+                }
+            };
+        }
+    }
+}
+ "#,
+        expect![[r#"
+macro_rules !matches {
+    ($expression: expr, $pattern: pat if $guard: expr) = > {
+        match $expression {
+            $pattern if $guard = > true , _ = > false
+        }
+    }
+    ;
+}
+fn main() {
+    /* error: unexpected token in input *//* parse error: expected expression */
+/* parse error: expected FAT_ARROW */
+/* parse error: expected `,` */
+/* parse error: expected pattern */
+match 0 {
+        0 if $guard=>true , _=>false
+    };
+}
+"#]],
+    );
+}
+
+#[test]
 fn test_dollar_crate_lhs_is_not_meta() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index b56dee3efb5..a528c4cc697 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -59,14 +59,14 @@ mod tests;
 
 use std::ops::Deref;
 
-use base_db::{CrateId, Edition, FileId};
+use base_db::{CrateId, FileId};
 use hir_expand::{
     name::Name, proc_macro::ProcMacroKind, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId,
 };
 use itertools::Itertools;
 use la_arena::Arena;
 use rustc_hash::{FxHashMap, FxHashSet};
-use span::{FileAstId, ROOT_ERASED_FILE_AST_ID};
+use span::{Edition, FileAstId, ROOT_ERASED_FILE_AST_ID};
 use stdx::format_to;
 use syntax::{ast, SmolStr};
 use triomphe::Arc;
@@ -737,7 +737,7 @@ impl MacroSubNs {
             MacroId::ProcMacroId(it) => {
                 return match it.lookup(db).kind {
                     ProcMacroKind::CustomDerive | ProcMacroKind::Attr => Self::Attr,
-                    ProcMacroKind::FuncLike => Self::Bang,
+                    ProcMacroKind::Bang => Self::Bang,
                 };
             }
         };
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs
index 662c80edf32..eb7f4c05ae2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs
@@ -136,6 +136,7 @@ pub(super) fn derive_macro_as_call_id(
     call_site: SyntaxContextId,
     krate: CrateId,
     resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
+    derive_macro_id: MacroCallId,
 ) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
     let (macro_id, def_id) = resolver(item_attr.path.clone())
         .filter(|(_, def_id)| def_id.is_derive())
@@ -147,6 +148,7 @@ pub(super) fn derive_macro_as_call_id(
             ast_id: item_attr.ast_id,
             derive_index: derive_pos,
             derive_attr_index,
+            derive_macro_id,
         },
         call_site,
     );
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 3d026447fb7..ae8f028e488 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
@@ -5,7 +5,7 @@
 
 use std::{cmp::Ordering, iter, mem, ops::Not};
 
-use base_db::{CrateId, Dependency, Edition, FileId};
+use base_db::{CrateId, Dependency, FileId};
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
 use hir_expand::{
@@ -22,9 +22,9 @@ use itertools::{izip, Itertools};
 use la_arena::Idx;
 use limit::Limit;
 use rustc_hash::{FxHashMap, FxHashSet};
-use span::{ErasedFileAstId, FileAstId, Span, SyntaxContextId};
+use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId};
 use stdx::always;
-use syntax::{ast, SmolStr};
+use syntax::ast;
 use triomphe::Arc;
 
 use crate::{
@@ -237,6 +237,8 @@ enum MacroDirectiveKind {
         derive_attr: AttrId,
         derive_pos: usize,
         ctxt: SyntaxContextId,
+        /// The "parent" macro it is resolved to.
+        derive_macro_id: MacroCallId,
     },
     Attr {
         ast_id: AstIdWithPath<ast::Item>,
@@ -312,7 +314,7 @@ impl DefCollector<'_> {
                     }
                 }
                 () if *attr_name == hir_expand::name![crate_type] => {
-                    if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) {
+                    if let Some("proc-macro") = attr.string_value() {
                         self.is_proc_macro = true;
                     }
                 }
@@ -602,7 +604,7 @@ impl DefCollector<'_> {
         .intern(self.db);
         self.define_proc_macro(def.name.clone(), proc_macro_id);
         let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap();
-        if let ProcMacroKind::CustomDerive { helpers } = def.kind {
+        if let ProcMacroKind::Derive { helpers } = def.kind {
             crate_data.exported_derives.insert(self.db.macro_def(proc_macro_id.into()), helpers);
         }
         crate_data.fn_proc_macro_mapping.insert(fn_id, proc_macro_id);
@@ -1146,7 +1148,13 @@ impl DefCollector<'_> {
                         return Resolved::Yes;
                     }
                 }
-                MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, ctxt: call_site } => {
+                MacroDirectiveKind::Derive {
+                    ast_id,
+                    derive_attr,
+                    derive_pos,
+                    ctxt: call_site,
+                    derive_macro_id,
+                } => {
                     let id = derive_macro_as_call_id(
                         self.db,
                         ast_id,
@@ -1155,6 +1163,7 @@ impl DefCollector<'_> {
                         *call_site,
                         self.def_map.krate,
                         resolver,
+                        *derive_macro_id,
                     );
 
                     if let Ok((macro_id, def_id, call_id)) = id {
@@ -1224,6 +1233,8 @@ impl DefCollector<'_> {
                         _ => return Resolved::No,
                     };
 
+                    let call_id =
+                        attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def);
                     if let MacroDefId {
                         kind:
                             MacroDefKind::BuiltInAttr(
@@ -1252,6 +1263,7 @@ impl DefCollector<'_> {
                                 return recollect_without(self);
                             }
                         };
+
                         let ast_id = ast_id.with_value(ast_adt_id);
 
                         match attr.parse_path_comma_token_tree(self.db.upcast()) {
@@ -1267,6 +1279,7 @@ impl DefCollector<'_> {
                                             derive_attr: attr.id,
                                             derive_pos: idx,
                                             ctxt: call_site.ctx,
+                                            derive_macro_id: call_id,
                                         },
                                         container: directive.container,
                                     });
@@ -1301,10 +1314,6 @@ impl DefCollector<'_> {
                         return recollect_without(self);
                     }
 
-                    // Not resolved to a derive helper or the derive attribute, so try to treat as a normal attribute.
-                    let call_id =
-                        attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def);
-
                     // Skip #[test]/#[bench] expansion, which would merely result in more memory usage
                     // due to duplicating functions into macro expansions
                     if matches!(
@@ -1460,13 +1469,20 @@ impl DefCollector<'_> {
                         ));
                     }
                 }
-                MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, ctxt: _ } => {
+                MacroDirectiveKind::Derive {
+                    ast_id,
+                    derive_attr,
+                    derive_pos,
+                    derive_macro_id,
+                    ..
+                } => {
                     self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
                         directive.module_id,
                         MacroCallKind::Derive {
                             ast_id: ast_id.ast_id,
                             derive_attr_index: *derive_attr,
                             derive_index: *derive_pos as u32,
+                            derive_macro_id: *derive_macro_id,
                         },
                         ast_id.path.clone(),
                     ));
@@ -1902,7 +1918,7 @@ impl ModCollector<'_, '_> {
     }
 
     fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
-        let path_attr = attrs.by_key("path").string_value().map(SmolStr::as_str);
+        let path_attr = attrs.by_key("path").string_value();
         let is_macro_use = attrs.by_key("macro_use").exists();
         let module = &self.item_tree[module_id];
         match &module.kind {
@@ -2146,7 +2162,7 @@ impl ModCollector<'_, '_> {
                 Some(it) => {
                     // FIXME: a hacky way to create a Name from string.
                     name = tt::Ident {
-                        text: it.clone(),
+                        text: it.into(),
                         span: Span {
                             range: syntax::TextRange::empty(syntax::TextSize::new(0)),
                             anchor: span::SpanAnchor {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index 9e53b037283..ee29b89f3d3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -10,8 +10,8 @@
 //!
 //! `ReachedFixedPoint` signals about this.
 
-use base_db::Edition;
 use hir_expand::{name::Name, Lookup};
+use span::Edition;
 use triomphe::Arc;
 
 use crate::{
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs
index c126fdac1c6..5052708dc93 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs
@@ -13,18 +13,16 @@ pub struct ProcMacroDef {
 
 #[derive(Debug, PartialEq, Eq)]
 pub enum ProcMacroKind {
-    CustomDerive { helpers: Box<[Name]> },
-    FnLike,
+    Derive { helpers: Box<[Name]> },
+    Bang,
     Attr,
 }
 
 impl ProcMacroKind {
     pub(super) fn to_basedb_kind(&self) -> hir_expand::proc_macro::ProcMacroKind {
         match self {
-            ProcMacroKind::CustomDerive { .. } => {
-                hir_expand::proc_macro::ProcMacroKind::CustomDerive
-            }
-            ProcMacroKind::FnLike => hir_expand::proc_macro::ProcMacroKind::FuncLike,
+            ProcMacroKind::Derive { .. } => hir_expand::proc_macro::ProcMacroKind::CustomDerive,
+            ProcMacroKind::Bang => hir_expand::proc_macro::ProcMacroKind::Bang,
             ProcMacroKind::Attr => hir_expand::proc_macro::ProcMacroKind::Attr,
         }
     }
@@ -34,13 +32,13 @@ impl Attrs {
     #[rustfmt::skip]
     pub fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> {
         if self.is_proc_macro() {
-            Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::FnLike })
+            Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Bang })
         } else if self.is_proc_macro_attribute() {
             Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr })
         } else if self.by_key("proc_macro_derive").exists() {
             let derive = self.by_key("proc_macro_derive").tt_values().next()?;
             let def = parse_macro_name_and_helper_attrs(&derive.token_trees)
-                .map(|(name, helpers)| ProcMacroDef { name, kind: ProcMacroKind::CustomDerive { helpers } });
+                .map(|(name, helpers)| ProcMacroDef { name, kind: ProcMacroKind::Derive { helpers } });
 
             if def.is_none() {
                 tracing::trace!("malformed `#[proc_macro_derive]`: {}", derive);
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 226d6f513f5..fadab858aa1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -24,6 +24,7 @@ use crate::{
     nameres::{DefMap, MacroSubNs},
     path::{ModPath, Path, PathKind},
     per_ns::PerNs,
+    type_ref::LifetimeRef,
     visibility::{RawVisibility, Visibility},
     AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
     ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId,
@@ -120,6 +121,12 @@ pub enum ValueNs {
     GenericParam(ConstParamId),
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum LifetimeNs {
+    Static,
+    LifetimeParam(LifetimeParamId),
+}
+
 impl Resolver {
     /// Resolve known trait from std, like `std::futures::Future`
     pub fn resolve_known_trait(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<TraitId> {
@@ -418,6 +425,19 @@ impl Resolver {
         self.resolve_path_as_macro(db, path, expected_macro_kind).map(|(it, _)| db.macro_def(it))
     }
 
+    pub fn resolve_lifetime(&self, lifetime: &LifetimeRef) -> Option<LifetimeNs> {
+        if lifetime.name == name::known::STATIC_LIFETIME {
+            return Some(LifetimeNs::Static);
+        }
+
+        self.scopes().find_map(|scope| match scope {
+            Scope::GenericParams { def, params } => {
+                params.find_lifetime_by_name(&lifetime.name, *def).map(LifetimeNs::LifetimeParam)
+            }
+            _ => None,
+        })
+    }
+
     /// Returns a set of names available in the current scope.
     ///
     /// Note that this is a somewhat fuzzy concept -- internally, the compiler
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index af3ecdcd5e3..f1540498f26 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -8,8 +8,8 @@ use intern::Interned;
 use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
 use smallvec::{smallvec, SmallVec};
 use span::{Span, SyntaxContextId};
-use syntax::{ast, match_ast, AstNode, AstToken, SmolStr, SyntaxNode};
-use triomphe::Arc;
+use syntax::{ast, format_smolstr, match_ast, AstNode, AstToken, SmolStr, SyntaxNode};
+use triomphe::ThinArc;
 
 use crate::{
     db::ExpandDatabase,
@@ -22,8 +22,7 @@ use crate::{
 /// Syntactical attributes, without filtering of `cfg_attr`s.
 #[derive(Default, Debug, Clone, PartialEq, Eq)]
 pub struct RawAttrs {
-    // FIXME: Make this a ThinArc
-    entries: Option<Arc<[Attr]>>,
+    entries: Option<ThinArc<(), Attr>>,
 }
 
 impl ops::Deref for RawAttrs {
@@ -31,7 +30,7 @@ impl ops::Deref for RawAttrs {
 
     fn deref(&self) -> &[Attr] {
         match &self.entries {
-            Some(it) => it,
+            Some(it) => &it.slice,
             None => &[],
         }
     }
@@ -45,20 +44,34 @@ impl RawAttrs {
         owner: &dyn ast::HasAttrs,
         span_map: SpanMapRef<'_>,
     ) -> Self {
-        let entries = collect_attrs(owner).filter_map(|(id, attr)| match attr {
-            Either::Left(attr) => {
-                attr.meta().and_then(|meta| Attr::from_src(db, meta, span_map, id))
-            }
-            Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
-                id,
-                input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))),
-                path: Interned::new(ModPath::from(crate::name!(doc))),
-                ctxt: span_map.span_for_range(comment.syntax().text_range()).ctx,
-            }),
-        });
-        let entries: Arc<[Attr]> = Arc::from_iter(entries);
+        let entries: Vec<_> = collect_attrs(owner)
+            .filter_map(|(id, attr)| match attr {
+                Either::Left(attr) => {
+                    attr.meta().and_then(|meta| Attr::from_src(db, meta, span_map, id))
+                }
+                Either::Right(comment) => comment.doc_comment().map(|doc| {
+                    let span = span_map.span_for_range(comment.syntax().text_range());
+                    Attr {
+                        id,
+                        input: Some(Interned::new(AttrInput::Literal(tt::Literal {
+                            // FIXME: Escape quotes from comment content
+                            text: SmolStr::new(format_smolstr!("\"{doc}\"",)),
+                            span,
+                        }))),
+                        path: Interned::new(ModPath::from(crate::name!(doc))),
+                        ctxt: span.ctx,
+                    }
+                }),
+            })
+            .collect();
 
-        Self { entries: if entries.is_empty() { None } else { Some(entries) } }
+        let entries = if entries.is_empty() {
+            None
+        } else {
+            Some(ThinArc::from_header_and_iter((), entries.into_iter()))
+        };
+
+        RawAttrs { entries }
     }
 
     pub fn from_attrs_owner(
@@ -75,16 +88,20 @@ impl RawAttrs {
             (None, entries @ Some(_)) => Self { entries },
             (Some(entries), None) => Self { entries: Some(entries.clone()) },
             (Some(a), Some(b)) => {
-                let last_ast_index = a.last().map_or(0, |it| it.id.ast_index() + 1) as u32;
-                Self {
-                    entries: Some(Arc::from_iter(a.iter().cloned().chain(b.iter().map(|it| {
+                let last_ast_index = a.slice.last().map_or(0, |it| it.id.ast_index() + 1) as u32;
+                let items = a
+                    .slice
+                    .iter()
+                    .cloned()
+                    .chain(b.slice.iter().map(|it| {
                         let mut it = it.clone();
                         it.id.id = (it.id.ast_index() as u32 + last_ast_index)
                             | (it.id.cfg_attr_index().unwrap_or(0) as u32)
                                 << AttrId::AST_INDEX_BITS;
                         it
-                    })))),
-                }
+                    }))
+                    .collect::<Vec<_>>();
+                Self { entries: Some(ThinArc::from_header_and_iter((), items.into_iter())) }
             }
         }
     }
@@ -100,41 +117,47 @@ impl RawAttrs {
         }
 
         let crate_graph = db.crate_graph();
-        let new_attrs = Arc::from_iter(self.iter().flat_map(|attr| -> SmallVec<[_; 1]> {
-            let is_cfg_attr =
-                attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]);
-            if !is_cfg_attr {
-                return smallvec![attr.clone()];
-            }
-
-            let subtree = match attr.token_tree_value() {
-                Some(it) => it,
-                _ => return smallvec![attr.clone()],
-            };
-
-            let (cfg, parts) = match parse_cfg_attr_input(subtree) {
-                Some(it) => it,
-                None => return smallvec![attr.clone()],
-            };
-            let index = attr.id;
-            let attrs = parts
-                .enumerate()
-                .take(1 << AttrId::CFG_ATTR_BITS)
-                .filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
-
-            let cfg_options = &crate_graph[krate].cfg_options;
-            let cfg = Subtree { delimiter: subtree.delimiter, token_trees: Box::from(cfg) };
-            let cfg = CfgExpr::parse(&cfg);
-            if cfg_options.check(&cfg) == Some(false) {
-                smallvec![]
-            } else {
-                cov_mark::hit!(cfg_attr_active);
-
-                attrs.collect()
-            }
-        }));
+        let new_attrs =
+            self.iter()
+                .flat_map(|attr| -> SmallVec<[_; 1]> {
+                    let is_cfg_attr =
+                        attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]);
+                    if !is_cfg_attr {
+                        return smallvec![attr.clone()];
+                    }
 
-        RawAttrs { entries: Some(new_attrs) }
+                    let subtree = match attr.token_tree_value() {
+                        Some(it) => it,
+                        _ => return smallvec![attr.clone()],
+                    };
+
+                    let (cfg, parts) = match parse_cfg_attr_input(subtree) {
+                        Some(it) => it,
+                        None => return smallvec![attr.clone()],
+                    };
+                    let index = attr.id;
+                    let attrs = parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map(
+                        |(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)),
+                    );
+
+                    let cfg_options = &crate_graph[krate].cfg_options;
+                    let cfg = Subtree { delimiter: subtree.delimiter, token_trees: Box::from(cfg) };
+                    let cfg = CfgExpr::parse(&cfg);
+                    if cfg_options.check(&cfg) == Some(false) {
+                        smallvec![]
+                    } else {
+                        cov_mark::hit!(cfg_attr_active);
+
+                        attrs.collect()
+                    }
+                })
+                .collect::<Vec<_>>();
+        let entries = if new_attrs.is_empty() {
+            None
+        } else {
+            Some(ThinArc::from_header_and_iter((), new_attrs.into_iter()))
+        };
+        RawAttrs { entries }
     }
 }
 
@@ -179,8 +202,7 @@ pub struct Attr {
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum AttrInput {
     /// `#[attr = "string"]`
-    // FIXME: This is losing span
-    Literal(SmolStr),
+    Literal(tt::Literal),
     /// `#[attr(subtree)]`
     TokenTree(Box<tt::Subtree>),
 }
@@ -188,7 +210,7 @@ pub enum AttrInput {
 impl fmt::Display for AttrInput {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            AttrInput::Literal(lit) => write!(f, " = \"{}\"", lit.escape_debug()),
+            AttrInput::Literal(lit) => write!(f, " = {lit}"),
             AttrInput::TokenTree(tt) => tt.fmt(f),
         }
     }
@@ -208,11 +230,10 @@ impl Attr {
         })?);
         let span = span_map.span_for_range(range);
         let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
-            let value = match lit.kind() {
-                ast::LiteralKind::String(string) => string.value()?.into(),
-                _ => lit.syntax().first_token()?.text().trim_matches('"').into(),
-            };
-            Some(Interned::new(AttrInput::Literal(value)))
+            Some(Interned::new(AttrInput::Literal(tt::Literal {
+                text: lit.token().text().into(),
+                span,
+            })))
         } else if let Some(tt) = ast.token_tree() {
             let tree = syntax_node_to_token_tree(tt.syntax(), span_map, span);
             Some(Interned::new(AttrInput::TokenTree(Box::new(tree))))
@@ -245,9 +266,8 @@ impl Attr {
             }
             Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '=', .. }))) => {
                 let input = match input.get(1) {
-                    Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { text, .. }))) => {
-                        //FIXME the trimming here isn't quite right, raw strings are not handled
-                        Some(Interned::new(AttrInput::Literal(text.trim_matches('"').into())))
+                    Some(tt::TokenTree::Leaf(tt::Leaf::Literal(lit))) => {
+                        Some(Interned::new(AttrInput::Literal(lit.clone())))
                     }
                     _ => None,
                 };
@@ -265,9 +285,14 @@ impl Attr {
 
 impl Attr {
     /// #[path = "string"]
-    pub fn string_value(&self) -> Option<&SmolStr> {
+    pub fn string_value(&self) -> Option<&str> {
         match self.input.as_deref()? {
-            AttrInput::Literal(it) => Some(it),
+            AttrInput::Literal(it) => match it.text.strip_prefix('r') {
+                Some(it) => it.trim_matches('#'),
+                None => it.text.as_str(),
+            }
+            .strip_prefix('"')?
+            .strip_suffix('"'),
             _ => None,
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
index 9fb6a0b2346..fd3e4e7a4db 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
@@ -1,11 +1,11 @@
 //! Builtin macro
 
-use base_db::{AnchoredPath, Edition, FileId};
+use base_db::{AnchoredPath, FileId};
 use cfg::CfgExpr;
 use either::Either;
 use itertools::Itertools;
 use mbe::{parse_exprs_with_sep, parse_to_token_tree};
-use span::{Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
+use span::{Edition, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
 use syntax::ast::{self, AstToken};
 
 use crate::{
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 c74c13a6fd3..db3558a84e9 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
@@ -10,7 +10,7 @@ use syntax::{
 use tracing::{debug, warn};
 use tt::SmolStr;
 
-use crate::{db::ExpandDatabase, MacroCallKind, MacroCallLoc};
+use crate::{db::ExpandDatabase, proc_macro::ProcMacroKind, MacroCallLoc, MacroDefKind};
 
 fn check_cfg_attr(attr: &Attr, loc: &MacroCallLoc, db: &dyn ExpandDatabase) -> Option<bool> {
     if !attr.simple_name().as_deref().map(|v| v == "cfg")? {
@@ -139,7 +139,7 @@ fn process_enum(
     'variant: for variant in variants.variants() {
         for attr in variant.attrs() {
             if check_cfg_attr(&attr, loc, db).map(|enabled| !enabled).unwrap_or_default() {
-                // Rustc does not strip the attribute if it is enabled. So we will will leave it
+                // Rustc does not strip the attribute if it is enabled. So we will leave it
                 debug!("censoring type {:?}", variant.syntax());
                 remove.insert(variant.syntax().clone().into());
                 // We need to remove the , as well
@@ -180,7 +180,13 @@ pub(crate) fn process_cfg_attrs(
     db: &dyn ExpandDatabase,
 ) -> Option<FxHashSet<SyntaxElement>> {
     // FIXME: #[cfg_eval] is not implemented. But it is not stable yet
-    if !matches!(loc.kind, MacroCallKind::Derive { .. }) {
+    let is_derive = match loc.def.kind {
+        MacroDefKind::BuiltInDerive(..)
+        | MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _) => true,
+        MacroDefKind::BuiltInAttr(expander, _) => expander.is_derive(),
+        _ => false,
+    };
+    if !is_derive {
         return None;
     }
     let mut remove = FxHashSet::default();
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index ec68f2f96e5..5461c1c49a3 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -24,7 +24,8 @@ use crate::{
     HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
     MacroFileId,
 };
-
+/// This is just to ensure the types of smart_macro_arg and macro_arg are the same
+type MacroArgResult = (Arc<tt::Subtree>, SyntaxFixupUndoInfo, Span);
 /// Total limit on the number of tokens produced by any macro invocation.
 ///
 /// If an invocation produces more tokens than this limit, it will not be stored in the database and
@@ -98,7 +99,13 @@ pub trait ExpandDatabase: SourceDatabase {
     /// Lowers syntactic macro call to a token tree representation. That's a firewall
     /// query, only typing in the macro call itself changes the returned
     /// subtree.
-    fn macro_arg(&self, id: MacroCallId) -> (Arc<tt::Subtree>, SyntaxFixupUndoInfo, Span);
+    fn macro_arg(&self, id: MacroCallId) -> MacroArgResult;
+    #[salsa::transparent]
+    fn macro_arg_considering_derives(
+        &self,
+        id: MacroCallId,
+        kind: &MacroCallKind,
+    ) -> MacroArgResult;
     /// Fetches the expander for this macro.
     #[salsa::transparent]
     #[salsa::invoke(TokenExpander::macro_expander)]
@@ -144,7 +151,7 @@ pub fn expand_speculative(
     let span_map = RealSpanMap::absolute(FileId::BOGUS);
     let span_map = SpanMapRef::RealSpanMap(&span_map);
 
-    let (_, _, span) = db.macro_arg(actual_macro_call);
+    let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
 
     // Build the subtree and token mapping for the speculative args
     let (mut tt, undo_info) = match loc.kind {
@@ -339,12 +346,24 @@ pub(crate) fn parse_with_map(
     }
 }
 
-// FIXME: for derive attributes, this will return separate copies of the same structures! Though
-// they may differ in spans due to differing call sites...
-fn macro_arg(
+/// This resolves the [MacroCallId] to check if it is a derive macro if so get the [macro_arg] for the derive.
+/// Other wise return the [macro_arg] for the macro_call_id.
+///
+/// This is not connected to the database so it does not cached the result. However, the inner [macro_arg] query is
+fn macro_arg_considering_derives(
     db: &dyn ExpandDatabase,
     id: MacroCallId,
-) -> (Arc<tt::Subtree>, SyntaxFixupUndoInfo, Span) {
+    kind: &MacroCallKind,
+) -> MacroArgResult {
+    match kind {
+        // Get the macro arg for the derive macro
+        MacroCallKind::Derive { derive_macro_id, .. } => db.macro_arg(*derive_macro_id),
+        // Normal macro arg
+        _ => db.macro_arg(id),
+    }
+}
+
+fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
     let loc = db.lookup_intern_macro_call(id);
 
     if let MacroCallLoc {
@@ -414,29 +433,30 @@ fn macro_arg(
             }
             return (Arc::new(tt), SyntaxFixupUndoInfo::NONE, span);
         }
-        MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
-            let node = ast_id.to_ptr(db).to_node(&root);
-            let censor_derive_input = censor_derive_input(derive_attr_index, &node);
-            let item_node = node.into();
-            let attr_source = attr_source(derive_attr_index, &item_node);
-            // FIXME: This is wrong, this should point to the path of the derive attribute`
-            let span =
-                map.span_for_range(attr_source.as_ref().and_then(|it| it.path()).map_or_else(
-                    || item_node.syntax().text_range(),
-                    |it| it.syntax().text_range(),
-                ));
-            (censor_derive_input, item_node, span)
+        // MacroCallKind::Derive should not be here. As we are getting the argument for the derive macro
+        MacroCallKind::Derive { .. } => {
+            unreachable!("`ExpandDatabase::macro_arg` called with `MacroCallKind::Derive`")
         }
         MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
             let node = ast_id.to_ptr(db).to_node(&root);
             let attr_source = attr_source(invoc_attr_index, &node);
+
             let span = map.span_for_range(
                 attr_source
                     .as_ref()
                     .and_then(|it| it.path())
                     .map_or_else(|| node.syntax().text_range(), |it| it.syntax().text_range()),
             );
-            (attr_source.into_iter().map(|it| it.syntax().clone().into()).collect(), node, span)
+            // If derive attribute we need to censor the derive input
+            if matches!(loc.def.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive())
+                && ast::Adt::can_cast(node.syntax().kind())
+            {
+                let adt = ast::Adt::cast(node.syntax().clone()).unwrap();
+                let censor_derive_input = censor_derive_input(invoc_attr_index, &adt);
+                (censor_derive_input, node, span)
+            } else {
+                (attr_source.into_iter().map(|it| it.syntax().clone().into()).collect(), node, span)
+            }
         }
     };
 
@@ -526,7 +546,8 @@ fn macro_expand(
     let (ExpandResult { value: tt, err }, span) = match loc.def.kind {
         MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc),
         _ => {
-            let (macro_arg, undo_info, span) = db.macro_arg(macro_call_id);
+            let (macro_arg, undo_info, span) =
+                db.macro_arg_considering_derives(macro_call_id, &loc.kind);
 
             let arg = &*macro_arg;
             let res =
@@ -603,7 +624,7 @@ fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
 
 fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> {
     let loc = db.lookup_intern_macro_call(id);
-    let (macro_arg, undo_info, span) = db.macro_arg(id);
+    let (macro_arg, undo_info, span) = db.macro_arg_considering_derives(id, &loc.kind);
 
     let (expander, ast) = match loc.def.kind {
         MacroDefKind::ProcMacro(expander, _, ast) => (expander, ast),
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
index 33643c02724..9a0b218e6d1 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
@@ -1,8 +1,8 @@
 //! Compiled declarative macro expanders (`macro_rules!`` and `macro`)
 use std::sync::OnceLock;
 
-use base_db::{CrateId, Edition, VersionReq};
-use span::{MacroCallId, Span};
+use base_db::{CrateId, VersionReq};
+use span::{MacroCallId, Span, SyntaxContextId};
 use syntax::{ast, AstNode};
 use triomphe::Arc;
 
@@ -10,13 +10,13 @@ use crate::{
     attrs::RawAttrs,
     db::ExpandDatabase,
     hygiene::{apply_mark, Transparency},
-    tt, AstId, ExpandError, ExpandResult,
+    tt, AstId, ExpandError, ExpandResult, Lookup,
 };
 
 /// Old-style `macro_rules` or the new macros 2.0
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct DeclarativeMacroExpander {
-    pub mac: mbe::DeclarativeMacro<span::Span>,
+    pub mac: mbe::DeclarativeMacro,
     pub transparency: Transparency,
 }
 
@@ -94,8 +94,6 @@ impl DeclarativeMacroExpander {
         def_crate: CrateId,
         id: AstId<ast::Macro>,
     ) -> Arc<DeclarativeMacroExpander> {
-        let crate_data = &db.crate_graph()[def_crate];
-        let is_2021 = crate_data.edition >= Edition::Edition2021;
         let (root, map) = crate::db::parse_with_map(db, id.file_id);
         let root = root.syntax_node();
 
@@ -133,6 +131,16 @@ impl DeclarativeMacroExpander {
             )
         });
 
+        let edition = |ctx: SyntaxContextId| {
+            let crate_graph = db.crate_graph();
+            if ctx.is_root() {
+                crate_graph[def_crate].edition
+            } else {
+                let data = db.lookup_intern_syntax_context(ctx);
+                // UNWRAP-SAFETY: Only the root context has no outer expansion
+                crate_graph[data.outer_expn.unwrap().lookup(db).def.krate].edition
+            }
+        };
         let (mac, transparency) = match id.to_ptr(db).to_node(&root) {
             ast::Macro::MacroRules(macro_rules) => (
                 match macro_rules.token_tree() {
@@ -145,12 +153,11 @@ impl DeclarativeMacroExpander {
                             ),
                         );
 
-                        mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021, new_meta_vars)
+                        mbe::DeclarativeMacro::parse_macro_rules(&tt, edition, new_meta_vars)
                     }
-                    None => mbe::DeclarativeMacro::from_err(
-                        mbe::ParseError::Expected("expected a token tree".into()),
-                        is_2021,
-                    ),
+                    None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected(
+                        "expected a token tree".into(),
+                    )),
                 },
                 transparency(&macro_rules).unwrap_or(Transparency::SemiTransparent),
             ),
@@ -163,12 +170,11 @@ impl DeclarativeMacroExpander {
                             map.span_for_range(macro_def.macro_token().unwrap().text_range()),
                         );
 
-                        mbe::DeclarativeMacro::parse_macro2(&tt, is_2021, new_meta_vars)
+                        mbe::DeclarativeMacro::parse_macro2(&tt, edition, new_meta_vars)
                     }
-                    None => mbe::DeclarativeMacro::from_err(
-                        mbe::ParseError::Expected("expected a token tree".into()),
-                        is_2021,
-                    ),
+                    None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected(
+                        "expected a token tree".into(),
+                    )),
                 },
                 transparency(&macro_def).unwrap_or(Transparency::Opaque),
             ),
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index 5d4f7dc1462..db8bbeccef8 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -30,10 +30,11 @@ use triomphe::Arc;
 
 use std::{fmt, hash::Hash};
 
-use base_db::{salsa::impl_intern_value_trivial, CrateId, Edition, FileId};
+use base_db::{salsa::impl_intern_value_trivial, CrateId, FileId};
 use either::Either;
 use span::{
-    ErasedFileAstId, FileRange, HirFileIdRepr, Span, SpanAnchor, SyntaxContextData, SyntaxContextId,
+    Edition, ErasedFileAstId, FileRange, HirFileIdRepr, Span, SpanAnchor, SyntaxContextData,
+    SyntaxContextId,
 };
 use syntax::{
     ast::{self, AstNode},
@@ -53,11 +54,9 @@ use crate::{
 
 pub use crate::files::{AstId, ErasedAstId, InFile, InMacroFile, InRealFile};
 
-pub use mbe::ValueResult;
+pub use mbe::{DeclarativeMacro, ValueResult};
 pub use span::{HirFileId, MacroCallId, MacroFileId};
 
-pub type DeclarativeMacro = ::mbe::DeclarativeMacro<tt::Span>;
-
 pub mod tt {
     pub use span::Span;
     pub use tt::{DelimiterKind, Spacing};
@@ -201,7 +200,7 @@ pub struct EagerCallInfo {
     /// Call id of the eager macro's input file (this is the macro file for its fully expanded input).
     arg_id: MacroCallId,
     error: Option<ExpandError>,
-    /// TODO: Doc
+    /// The call site span of the eager macro
     span: Span,
 }
 
@@ -212,7 +211,7 @@ pub enum MacroCallKind {
         expand_to: ExpandTo,
         /// Some if this is a macro call for an eager macro. Note that this is `None`
         /// for the eager input macro file.
-        // FIXME: This is being interned, subtrees can vary quickly differ just slightly causing
+        // FIXME: This is being interned, subtrees can vary quickly differing just slightly causing
         // leakage problems here
         eager: Option<Arc<EagerCallInfo>>,
     },
@@ -225,6 +224,9 @@ pub enum MacroCallKind {
         derive_attr_index: AttrId,
         /// Index of the derive macro in the derive attribute
         derive_index: u32,
+        /// The "parent" macro call.
+        /// We will resolve the same token tree for all derive macros in the same derive attribute.
+        derive_macro_id: MacroCallId,
     },
     Attr {
         ast_id: AstId<ast::Item>,
@@ -484,7 +486,7 @@ impl MacroDefId {
         matches!(
             self.kind,
             MacroDefKind::BuiltIn(..)
-                | MacroDefKind::ProcMacro(_, ProcMacroKind::FuncLike, _)
+                | MacroDefKind::ProcMacro(_, ProcMacroKind::Bang, _)
                 | MacroDefKind::BuiltInEager(..)
                 | MacroDefKind::Declarative(..)
         )
@@ -806,7 +808,8 @@ impl ExpansionInfo {
         let (parse, exp_map) = db.parse_macro_expansion(macro_file).value;
         let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() };
 
-        let (macro_arg, _, _) = db.macro_arg(macro_file.macro_call_id);
+        let (macro_arg, _, _) =
+            db.macro_arg_considering_derives(macro_file.macro_call_id, &loc.kind);
 
         let def = loc.def.ast_id().left().and_then(|id| {
             let def_tt = match id.to_node(db) {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
index fc186d2c26d..46f8c2b9d8c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
@@ -225,6 +225,26 @@ fn convert_path(
     let mut segments = path.segments();
 
     let segment = &segments.next()?;
+    let handle_super_kw = &mut |init_deg| {
+        let mut deg = init_deg;
+        let mut next_segment = None;
+        for segment in segments.by_ref() {
+            match segment.kind()? {
+                ast::PathSegmentKind::SuperKw => deg += 1,
+                ast::PathSegmentKind::Name(name) => {
+                    next_segment = Some(name.as_name());
+                    break;
+                }
+                ast::PathSegmentKind::Type { .. }
+                | ast::PathSegmentKind::SelfTypeKw
+                | ast::PathSegmentKind::SelfKw
+                | ast::PathSegmentKind::CrateKw => return None,
+            }
+        }
+
+        Some(ModPath::from_segments(PathKind::Super(deg), next_segment))
+    };
+
     let mut mod_path = match segment.kind()? {
         ast::PathSegmentKind::Name(name_ref) => {
             if name_ref.text() == "$crate" {
@@ -245,26 +265,8 @@ fn convert_path(
             ModPath::from_segments(PathKind::Plain, Some(known::SELF_TYPE))
         }
         ast::PathSegmentKind::CrateKw => ModPath::from_segments(PathKind::Crate, iter::empty()),
-        ast::PathSegmentKind::SelfKw => ModPath::from_segments(PathKind::Super(0), iter::empty()),
-        ast::PathSegmentKind::SuperKw => {
-            let mut deg = 1;
-            let mut next_segment = None;
-            for segment in segments.by_ref() {
-                match segment.kind()? {
-                    ast::PathSegmentKind::SuperKw => deg += 1,
-                    ast::PathSegmentKind::Name(name) => {
-                        next_segment = Some(name.as_name());
-                        break;
-                    }
-                    ast::PathSegmentKind::Type { .. }
-                    | ast::PathSegmentKind::SelfTypeKw
-                    | ast::PathSegmentKind::SelfKw
-                    | ast::PathSegmentKind::CrateKw => return None,
-                }
-            }
-
-            ModPath::from_segments(PathKind::Super(deg), next_segment)
-        }
+        ast::PathSegmentKind::SelfKw => handle_super_kw(0)?,
+        ast::PathSegmentKind::SuperKw => handle_super_kw(1)?,
         ast::PathSegmentKind::Type { .. } => {
             // not allowed in imports
             return None;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
index ca6fc0afe2d..abed16fecde 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
@@ -23,7 +23,7 @@ impl ProcMacroId {
 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
 pub enum ProcMacroKind {
     CustomDerive,
-    FuncLike,
+    Bang,
     Attr,
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index 3cfedcdcb4d..bf473740166 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -47,13 +47,14 @@ hir-expand.workspace = true
 base-db.workspace = true
 syntax.workspace = true
 limit.workspace = true
+span.workspace = true
 
 [dev-dependencies]
 expect-test = "1.4.0"
 tracing.workspace = true
 tracing-subscriber.workspace = true
 tracing-tree.workspace = true
-project-model = { path = "../project-model" }
+project-model.workspace = true
 
 # local deps
 test-utils.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
index c485c9b2e80..cb118a36848 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
@@ -9,21 +9,21 @@ use chalk_ir::{
     AdtId, DebruijnIndex, Scalar,
 };
 use hir_def::{
-    builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId,
-    GenericDefId, TraitId, TypeAliasId,
+    builtin_type::BuiltinType, DefWithBodyId, GenericDefId, GenericParamId, TraitId, TypeAliasId,
 };
 use smallvec::SmallVec;
 
 use crate::{
-    consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
-    to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, BoundVar, CallableSig,
-    GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt,
-    TyKind,
+    consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime,
+    infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics,
+    Binders, BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy,
+    Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum ParamKind {
     Type,
+    Lifetime,
     Const(Ty),
 }
 
@@ -107,6 +107,9 @@ impl<D> TyBuilder<D> {
             ParamKind::Const(ty) => {
                 BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
             }
+            ParamKind::Lifetime => {
+                BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
+            }
         });
         this.vec.extend(filler.take(this.remaining()).casted(Interner));
         assert_eq!(this.remaining(), 0);
@@ -119,6 +122,7 @@ impl<D> TyBuilder<D> {
         let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
             ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
             ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+            ParamKind::Lifetime => error_lifetime().cast(Interner),
         });
         this.vec.extend(filler.casted(Interner));
         assert_eq!(this.remaining(), 0);
@@ -130,6 +134,7 @@ impl<D> TyBuilder<D> {
         self.fill(|x| match x {
             ParamKind::Type => table.new_type_var().cast(Interner),
             ParamKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
+            ParamKind::Lifetime => table.new_lifetime_var().cast(Interner),
         })
     }
 
@@ -142,7 +147,8 @@ impl<D> TyBuilder<D> {
     fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
         match (a.data(Interner), e) {
             (GenericArgData::Ty(_), ParamKind::Type)
-            | (GenericArgData::Const(_), ParamKind::Const(_)) => (),
+            | (GenericArgData::Const(_), ParamKind::Const(_))
+            | (GenericArgData::Lifetime(_), ParamKind::Lifetime) => (),
             _ => panic!("Mismatched kinds: {a:?}, {:?}, {:?}", self.vec, self.param_kinds),
         }
     }
@@ -201,10 +207,11 @@ impl TyBuilder<()> {
         Substitution::from_iter(
             Interner,
             params.iter_id().map(|id| match id {
-                either::Either::Left(_) => TyKind::Error.intern(Interner).cast(Interner),
-                either::Either::Right(id) => {
+                GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
+                GenericParamId::ConstParamId(id) => {
                     unknown_const_as_generic(db.const_param_ty(id)).cast(Interner)
                 }
+                GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
             }),
         )
     }
@@ -219,11 +226,10 @@ impl TyBuilder<()> {
         assert!(generics.parent_generics().is_some() == parent_subst.is_some());
         let params = generics
             .iter_self()
-            .map(|(id, data)| match data {
-                TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
-                TypeOrConstParamData::ConstParamData(_) => {
-                    ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
-                }
+            .map(|(id, _data)| match id {
+                GenericParamId::TypeParamId(_) => ParamKind::Type,
+                GenericParamId::ConstParamId(id) => ParamKind::Const(db.const_param_ty(id)),
+                GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
             })
             .collect();
         TyBuilder::new((), params, parent_subst)
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 e678a2fee13..46612242b09 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
@@ -272,6 +272,19 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
                 };
                 chalk_ir::Binders::new(binders, bound)
             }
+            crate::ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
+                let datas = self
+                    .db
+                    .type_alias_impl_traits(alias)
+                    .expect("impl trait id without impl traits");
+                let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
+                let data = &datas.impl_traits[idx];
+                let bound = OpaqueTyDatumBound {
+                    bounds: make_single_type_binders(data.bounds.skip_binders().to_vec()),
+                    where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
+                };
+                chalk_ir::Binders::new(binders, bound)
+            }
             crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
                 if let Some((future_trait, future_output)) = self
                     .db
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index 795a5996912..d1aebeff261 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -268,6 +268,13 @@ impl TyExt for Ty {
                             data.substitute(Interner, &subst).into_value_and_skipped_binders().0
                         })
                     }
+                    ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
+                        db.type_alias_impl_traits(alias).map(|it| {
+                            let data =
+                                (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
+                            data.substitute(Interner, &subst).into_value_and_skipped_binders().0
+                        })
+                    }
                 }
             }
             TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
@@ -280,6 +287,13 @@ impl TyExt for Ty {
                             data.substitute(Interner, &opaque_ty.substitution)
                         })
                     }
+                    ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
+                        db.type_alias_impl_traits(alias).map(|it| {
+                            let data =
+                                (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
+                            data.substitute(Interner, &opaque_ty.substitution)
+                        })
+                    }
                     // It always has an parameter for Future::Output type.
                     ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
                 };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index 98384c47490..d1ffd5046c3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -2825,3 +2825,30 @@ fn unsized_local() {
         |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::UnsizedTemporary(_))),
     );
 }
+
+#[test]
+fn recursive_adt() {
+    check_fail(
+        r#"
+        //- minicore: coerce_unsized, index, slice
+        pub enum TagTree {
+            Leaf,
+            Choice(&'static [TagTree]),
+        }
+        const GOAL: TagTree = {
+            const TAG_TREE: TagTree = TagTree::Choice(&[
+                {
+                    const VARIANT_TAG_TREE: TagTree = TagTree::Choice(
+                        &[
+                            TagTree::Leaf,
+                        ],
+                    );
+                    VARIANT_TAG_TREE
+                },
+            ]);
+            TAG_TREE
+        };
+    "#,
+        |e| matches!(e, ConstEvalError::MirEvalError(MirEvalError::StackOverflow)),
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 28c497989fe..90bf46b5056 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -11,7 +11,7 @@ use base_db::{
 use hir_def::{
     db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, ConstParamId,
     DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId,
-    LifetimeParamId, LocalFieldId, StaticId, TypeOrConstParamId, VariantId,
+    LifetimeParamId, LocalFieldId, StaticId, TypeAliasId, TypeOrConstParamId, VariantId,
 };
 use la_arena::ArenaMap;
 use smallvec::SmallVec;
@@ -23,9 +23,9 @@ use crate::{
     layout::{Layout, LayoutError},
     method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
     mir::{BorrowckResult, MirBody, MirLowerError},
-    Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, InferenceResult,
-    Interner, PolyFnSig, QuantifiedWhereClause, ReturnTypeImplTraits, Substitution,
-    TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId,
+    Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, ImplTraits,
+    InferenceResult, Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment,
+    TraitRef, Ty, TyDefId, ValueTyDefId,
 };
 use hir_expand::name::Name;
 
@@ -132,10 +132,10 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
 
     #[salsa::invoke(crate::lower::return_type_impl_traits)]
-    fn return_type_impl_traits(
-        &self,
-        def: FunctionId,
-    ) -> Option<Arc<Binders<ReturnTypeImplTraits>>>;
+    fn return_type_impl_traits(&self, def: FunctionId) -> Option<Arc<Binders<ImplTraits>>>;
+
+    #[salsa::invoke(crate::lower::type_alias_impl_traits)]
+    fn type_alias_impl_traits(&self, def: TypeAliasId) -> Option<Arc<Binders<ImplTraits>>>;
 
     #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
     #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
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 67cfbc294df..20b0da441da 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
@@ -11,7 +11,6 @@ use hir_def::{ItemContainerId, Lookup};
 use hir_expand::name;
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
-use rustc_pattern_analysis::usefulness::{compute_match_usefulness, ValidityConstraint};
 use syntax::{ast, AstNode};
 use tracing::debug;
 use triomphe::Arc;
@@ -234,13 +233,7 @@ impl ExprValidator {
             return;
         }
 
-        let report = match compute_match_usefulness(
-            &cx,
-            m_arms.as_slice(),
-            scrut_ty.clone(),
-            ValidityConstraint::ValidOnly,
-            None,
-        ) {
+        let report = match cx.compute_match_usefulness(m_arms.as_slice(), scrut_ty.clone()) {
             Ok(report) => report,
             Err(()) => return,
         };
@@ -282,13 +275,7 @@ impl ExprValidator {
                 continue;
             }
 
-            let report = match compute_match_usefulness(
-                &cx,
-                &[match_arm],
-                ty.clone(),
-                ValidityConstraint::ValidOnly,
-                None,
-            ) {
+            let report = match cx.compute_match_usefulness(&[match_arm], ty.clone()) {
                 Ok(v) => v,
                 Err(e) => {
                     debug!(?e, "match usefulness error");
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 ca058428796..f45beb4c92b 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
@@ -8,7 +8,8 @@ use rustc_hash::FxHashMap;
 use rustc_pattern_analysis::{
     constructor::{Constructor, ConstructorSet, VariantVisibility},
     index::IdxContainer,
-    Captures, PrivateUninhabitedField, TypeCx,
+    usefulness::{compute_match_usefulness, PlaceValidity, UsefulnessReport},
+    Captures, PatCx, PrivateUninhabitedField,
 };
 use smallvec::{smallvec, SmallVec};
 use stdx::never;
@@ -59,6 +60,18 @@ impl<'p> MatchCheckCtx<'p> {
         Self { module, body, db, exhaustive_patterns, min_exhaustive_patterns }
     }
 
+    pub(crate) fn compute_match_usefulness(
+        &self,
+        arms: &[MatchArm<'p>],
+        scrut_ty: Ty,
+    ) -> Result<UsefulnessReport<'p, Self>, ()> {
+        // FIXME: Determine place validity correctly. For now, err on the safe side.
+        let place_validity = PlaceValidity::MaybeInvalid;
+        // Measured to take ~100ms on modern hardware.
+        let complexity_limit = Some(500000);
+        compute_match_usefulness(self, arms, scrut_ty, place_validity, complexity_limit)
+    }
+
     fn is_uninhabited(&self, ty: &Ty) -> bool {
         is_ty_uninhabited_from(ty, self.module, self.db)
     }
@@ -107,15 +120,17 @@ impl<'p> MatchCheckCtx<'p> {
     }
 
     pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'p> {
-        let singleton = |pat| vec![pat];
+        let singleton = |pat: DeconstructedPat<'p>| vec![pat.at_index(0)];
         let ctor;
-        let fields: Vec<_>;
+        let mut fields: Vec<_>;
+        let arity;
 
         match pat.kind.as_ref() {
             PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
                 fields = Vec::new();
+                arity = 0;
             }
             PatKind::Deref { subpattern } => {
                 ctor = match pat.ty.kind(Interner) {
@@ -128,23 +143,22 @@ impl<'p> MatchCheckCtx<'p> {
                     }
                 };
                 fields = singleton(self.lower_pat(subpattern));
+                arity = 1;
             }
             PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
+                fields = subpatterns
+                    .iter()
+                    .map(|pat| {
+                        let idx: u32 = pat.field.into_raw().into();
+                        self.lower_pat(&pat.pattern).at_index(idx as usize)
+                    })
+                    .collect();
                 match pat.ty.kind(Interner) {
                     TyKind::Tuple(_, substs) => {
                         ctor = Struct;
-                        let mut wilds: Vec<_> = substs
-                            .iter(Interner)
-                            .map(|arg| arg.assert_ty_ref(Interner).clone())
-                            .map(DeconstructedPat::wildcard)
-                            .collect();
-                        for pat in subpatterns {
-                            let idx: u32 = pat.field.into_raw().into();
-                            wilds[idx as usize] = self.lower_pat(&pat.pattern);
-                        }
-                        fields = wilds
+                        arity = substs.len(Interner);
                     }
-                    TyKind::Adt(adt, substs) if is_box(self.db, adt.0) => {
+                    TyKind::Adt(adt, _) if is_box(self.db, adt.0) => {
                         // The only legal patterns of type `Box` (outside `std`) are `_` and box
                         // patterns. If we're here we can assume this is a box pattern.
                         // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_,
@@ -157,16 +171,9 @@ impl<'p> MatchCheckCtx<'p> {
                         // normally or through box-patterns. We'll have to figure out a proper
                         // solution when we introduce generalized deref patterns. Also need to
                         // prevent mixing of those two options.
-                        let pat =
-                            subpatterns.iter().find(|pat| pat.field.into_raw() == 0u32.into());
-                        let field = if let Some(pat) = pat {
-                            self.lower_pat(&pat.pattern)
-                        } else {
-                            let ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone();
-                            DeconstructedPat::wildcard(ty)
-                        };
+                        fields.retain(|ipat| ipat.idx == 0);
                         ctor = Struct;
-                        fields = singleton(field);
+                        arity = 1;
                     }
                     &TyKind::Adt(adt, _) => {
                         ctor = match pat.kind.as_ref() {
@@ -181,37 +188,33 @@ impl<'p> MatchCheckCtx<'p> {
                             }
                         };
                         let variant = Self::variant_id_for_adt(&ctor, adt.0).unwrap();
-                        // Fill a vec with wildcards, then place the fields we have at the right
-                        // index.
-                        let mut wilds: Vec<_> = self
-                            .list_variant_fields(&pat.ty, variant)
-                            .map(|(_, ty)| ty)
-                            .map(DeconstructedPat::wildcard)
-                            .collect();
-                        for pat in subpatterns {
-                            let field_id: u32 = pat.field.into_raw().into();
-                            wilds[field_id as usize] = self.lower_pat(&pat.pattern);
-                        }
-                        fields = wilds;
+                        arity = variant.variant_data(self.db.upcast()).fields().len();
                     }
                     _ => {
                         never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty);
                         ctor = Wildcard;
-                        fields = Vec::new();
+                        fields.clear();
+                        arity = 0;
                     }
                 }
             }
             &PatKind::LiteralBool { value } => {
                 ctor = Bool(value);
                 fields = Vec::new();
+                arity = 0;
             }
             PatKind::Or { pats } => {
                 ctor = Or;
-                fields = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+                fields = pats
+                    .iter()
+                    .enumerate()
+                    .map(|(i, pat)| self.lower_pat(pat).at_index(i))
+                    .collect();
+                arity = pats.len();
             }
         }
         let data = PatData { db: self.db };
-        DeconstructedPat::new(ctor, fields, pat.ty.clone(), data)
+        DeconstructedPat::new(ctor, fields, arity, pat.ty.clone(), data)
     }
 
     pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'p>) -> Pat {
@@ -271,7 +274,7 @@ impl<'p> MatchCheckCtx<'p> {
     }
 }
 
-impl<'p> TypeCx for MatchCheckCtx<'p> {
+impl<'p> PatCx for MatchCheckCtx<'p> {
     type Error = ();
     type Ty = Ty;
     type VariantIdx = EnumVariantId;
@@ -453,7 +456,7 @@ impl<'p> TypeCx for MatchCheckCtx<'p> {
         let variant =
             pat.ty().as_adt().and_then(|(adt, _)| Self::variant_id_for_adt(pat.ctor(), adt));
 
-        let db = pat.data().unwrap().db;
+        let db = pat.data().db;
         if let Some(variant) = variant {
             match variant {
                 VariantId::EnumVariantId(v) => {
@@ -475,7 +478,6 @@ impl<'p> TypeCx for MatchCheckCtx<'p> {
     }
 
     fn complexity_exceeded(&self) -> Result<(), Self::Error> {
-        // FIXME(Nadrieril): make use of the complexity counter.
         Err(())
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 20964f5acbd..8740ae6797c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -938,18 +938,32 @@ impl HirDisplay for Ty {
                 f.end_location_link();
                 if parameters.len(Interner) > 0 {
                     let generics = generics(db.upcast(), def.into());
-                    let (parent_params, self_param, type_params, const_params, _impl_trait_params) =
-                        generics.provenance_split();
-                    let total_len = parent_params + self_param + type_params + const_params;
+                    let (
+                        parent_params,
+                        self_param,
+                        type_params,
+                        const_params,
+                        _impl_trait_params,
+                        lifetime_params,
+                    ) = generics.provenance_split();
+                    let total_len =
+                        parent_params + self_param + type_params + const_params + lifetime_params;
                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
                     if total_len > 0 {
-                        // `parameters` are in the order of fn's params (including impl traits),
+                        // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes
                         // parent's params (those from enclosing impl or trait, if any).
                         let parameters = parameters.as_slice(Interner);
                         let fn_params_len = self_param + type_params + const_params;
+                        // This will give slice till last type or const
                         let fn_params = parameters.get(..fn_params_len);
+                        let fn_lt_params =
+                            parameters.get(fn_params_len..(fn_params_len + lifetime_params));
                         let parent_params = parameters.get(parameters.len() - parent_params..);
-                        let params = parent_params.into_iter().chain(fn_params).flatten();
+                        let params = parent_params
+                            .into_iter()
+                            .chain(fn_lt_params)
+                            .chain(fn_params)
+                            .flatten();
                         write!(f, "<")?;
                         f.write_joined(params, ", ")?;
                         write!(f, ">")?;
@@ -1063,6 +1077,20 @@ impl HirDisplay for Ty {
                         )?;
                         // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
                     }
+                    ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
+                        let datas =
+                            db.type_alias_impl_traits(alias).expect("impl trait id without data");
+                        let data =
+                            (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
+                        let bounds = data.substitute(Interner, &parameters);
+                        let krate = alias.krate(db.upcast());
+                        write_bounds_like_dyn_trait_with_prefix(
+                            f,
+                            "impl",
+                            bounds.skip_binders(),
+                            SizedByDefault::Sized { anchor: krate },
+                        )?;
+                    }
                     ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => {
                         let future_trait = db
                             .lang_item(body.module(db.upcast()).krate(), LangItem::Future)
@@ -1228,6 +1256,20 @@ impl HirDisplay for Ty {
                             SizedByDefault::Sized { anchor: krate },
                         )?;
                     }
+                    ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
+                        let datas =
+                            db.type_alias_impl_traits(alias).expect("impl trait id without data");
+                        let data =
+                            (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
+                        let bounds = data.substitute(Interner, &opaque_ty.substitution);
+                        let krate = alias.krate(db.upcast());
+                        write_bounds_like_dyn_trait_with_prefix(
+                            f,
+                            "impl",
+                            bounds.skip_binders(),
+                            SizedByDefault::Sized { anchor: krate },
+                        )?;
+                    }
                     ImplTraitId::AsyncBlockTypeImplTrait(..) => {
                         write!(f, "{{async block}}")?;
                     }
@@ -1280,8 +1322,17 @@ fn hir_fmt_generics(
     generic_def: Option<hir_def::GenericDefId>,
 ) -> Result<(), HirDisplayError> {
     let db = f.db;
-    let lifetime_args_count = generic_def.map_or(0, |g| db.generic_params(g).lifetimes.len());
-    if parameters.len(Interner) + lifetime_args_count > 0 {
+    if parameters.len(Interner) > 0 {
+        use std::cmp::Ordering;
+        let param_compare =
+            |a: &GenericArg, b: &GenericArg| match (a.data(Interner), b.data(Interner)) {
+                (crate::GenericArgData::Lifetime(_), crate::GenericArgData::Lifetime(_)) => {
+                    Ordering::Equal
+                }
+                (crate::GenericArgData::Lifetime(_), _) => Ordering::Less,
+                (_, crate::GenericArgData::Lifetime(_)) => Ordering::Less,
+                (_, _) => Ordering::Equal,
+            };
         let parameters_to_write = if f.display_target.is_source_code() || f.omit_verbose_types() {
             match generic_def
                 .map(|generic_def_id| db.generic_defaults(generic_def_id))
@@ -1307,6 +1358,11 @@ fn hir_fmt_generics(
                                 return true;
                             }
                         }
+                        if parameter.lifetime(Interner).map(|it| it.data(Interner))
+                            == Some(&crate::LifetimeData::Static)
+                        {
+                            return true;
+                        }
                         let default_parameter = match default_parameters.get(i) {
                             Some(it) => it,
                             None => return true,
@@ -1327,16 +1383,12 @@ fn hir_fmt_generics(
         } else {
             parameters.as_slice(Interner)
         };
-        if !parameters_to_write.is_empty() || lifetime_args_count != 0 {
+        //FIXME: Should handle the ordering of lifetimes when creating substitutions
+        let mut parameters_to_write = parameters_to_write.to_vec();
+        parameters_to_write.sort_by(param_compare);
+        if !parameters_to_write.is_empty() {
             write!(f, "<")?;
             let mut first = true;
-            for _ in 0..lifetime_args_count {
-                if !first {
-                    write!(f, ", ")?;
-                }
-                first = false;
-                write!(f, "'_")?;
-            }
             for generic_arg in parameters_to_write {
                 if !first {
                     write!(f, ", ")?;
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 34ba17f145e..be3b50e1411 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -25,8 +25,11 @@ pub(crate) mod unify;
 use std::{convert::identity, iter, ops::Index};
 
 use chalk_ir::{
-    cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety,
-    Scalar, TyKind, TypeFlags, Variance,
+    cast::Cast,
+    fold::TypeFoldable,
+    interner::HasInterner,
+    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
+    DebruijnIndex, Mutability, Safety, Scalar, TyKind, TypeFlags, Variance,
 };
 use either::Either;
 use hir_def::{
@@ -39,7 +42,7 @@ use hir_def::{
     layout::Integer,
     path::{ModPath, Path},
     resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
-    type_ref::TypeRef,
+    type_ref::{LifetimeRef, TypeRef},
     AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, Lookup, TraitId,
     TupleFieldId, TupleId, TypeAliasId, VariantId,
 };
@@ -53,14 +56,14 @@ use triomphe::Arc;
 use crate::{
     db::HirDatabase,
     fold_tys,
-    infer::coerce::CoerceMany,
+    infer::{coerce::CoerceMany, unify::InferenceTable},
     lower::ImplTraitLoweringMode,
     static_lifetime, to_assoc_type_id,
     traits::FnTrait,
     utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
     AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
-    InEnvironment, Interner, Lifetime, ProjectionTy, RpitId, Substitution, TraitEnvironment,
-    TraitRef, Ty, TyBuilder, TyExt,
+    ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution,
+    TraitEnvironment, Ty, TyBuilder, TyExt,
 };
 
 // This lint has a false positive here. See the link below for details.
@@ -422,7 +425,7 @@ pub struct InferenceResult {
     /// unresolved or missing subpatterns or subpatterns of mismatched types.
     pub type_of_pat: ArenaMap<PatId, Ty>,
     pub type_of_binding: ArenaMap<BindingId, Ty>,
-    pub type_of_rpit: ArenaMap<RpitId, Ty>,
+    pub type_of_rpit: ArenaMap<ImplTraitIdx, Ty>,
     /// Type of the result of `.into_iter()` on the for. `ExprId` is the one of the whole for loop.
     pub type_of_for_iterator: FxHashMap<ExprId, Ty>,
     type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
@@ -752,7 +755,12 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn collect_const(&mut self, data: &ConstData) {
-        self.return_ty = self.make_ty(&data.type_ref);
+        let return_ty = self.make_ty(&data.type_ref);
+
+        // Constants might be associated items that define ATPITs.
+        self.insert_atpit_coercion_table(iter::once(&return_ty));
+
+        self.return_ty = return_ty;
     }
 
     fn collect_static(&mut self, data: &StaticData) {
@@ -785,11 +793,13 @@ impl<'a> InferenceContext<'a> {
                 self.write_binding_ty(self_param, ty);
             }
         }
+        let mut params_and_ret_tys = Vec::new();
         for (ty, pat) in param_tys.zip(&*self.body.params) {
             let ty = self.insert_type_vars(ty);
             let ty = self.normalize_associated_types_in(ty);
 
             self.infer_top_pat(*pat, &ty);
+            params_and_ret_tys.push(ty);
         }
         let return_ty = &*data.ret_type;
 
@@ -801,8 +811,11 @@ impl<'a> InferenceContext<'a> {
         let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
             // RPIT opaque types use substitution of their parent function.
             let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
-            let result =
-                self.insert_inference_vars_for_rpit(return_ty, rpits.clone(), fn_placeholders);
+            let result = self.insert_inference_vars_for_impl_trait(
+                return_ty,
+                rpits.clone(),
+                fn_placeholders,
+            );
             let rpits = rpits.skip_binders();
             for (id, _) in rpits.impl_traits.iter() {
                 if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) {
@@ -817,13 +830,19 @@ impl<'a> InferenceContext<'a> {
 
         self.return_ty = self.normalize_associated_types_in(return_ty);
         self.return_coercion = Some(CoerceMany::new(self.return_ty.clone()));
+
+        // Functions might be associated items that define ATPITs.
+        // To define an ATPITs, that ATPIT must appear in the function's signatures.
+        // So, it suffices to check for params and return types.
+        params_and_ret_tys.push(self.return_ty.clone());
+        self.insert_atpit_coercion_table(params_and_ret_tys.iter());
     }
 
-    fn insert_inference_vars_for_rpit<T>(
+    fn insert_inference_vars_for_impl_trait<T>(
         &mut self,
         t: T,
-        rpits: Arc<chalk_ir::Binders<crate::ReturnTypeImplTraits>>,
-        fn_placeholders: Substitution,
+        rpits: Arc<chalk_ir::Binders<crate::ImplTraits>>,
+        placeholders: Substitution,
     ) -> T
     where
         T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>,
@@ -837,6 +856,7 @@ impl<'a> InferenceContext<'a> {
                 };
                 let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
                     ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
+                    ImplTraitId::AssociatedTypeImplTrait(_, idx) => idx,
                     _ => unreachable!(),
                 };
                 let bounds =
@@ -844,15 +864,14 @@ impl<'a> InferenceContext<'a> {
                 let var = self.table.new_type_var();
                 let var_subst = Substitution::from1(Interner, var.clone());
                 for bound in bounds {
-                    let predicate =
-                        bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders);
+                    let predicate = bound.map(|it| it.cloned()).substitute(Interner, &placeholders);
                     let (var_predicate, binders) =
                         predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders();
                     always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
-                    let var_predicate = self.insert_inference_vars_for_rpit(
+                    let var_predicate = self.insert_inference_vars_for_impl_trait(
                         var_predicate,
                         rpits.clone(),
-                        fn_placeholders.clone(),
+                        placeholders.clone(),
                     );
                     self.push_obligation(var_predicate.cast(Interner));
                 }
@@ -863,6 +882,106 @@ impl<'a> InferenceContext<'a> {
         )
     }
 
+    /// The coercion of a non-inference var into an opaque type should fail,
+    /// but not in the defining sites of the ATPITs.
+    /// In such cases, we insert an proxy inference var for each ATPIT,
+    /// and coerce into it instead of ATPIT itself.
+    ///
+    /// The inference var stretagy is effective because;
+    ///
+    /// - It can still unify types that coerced into ATPIT
+    /// - We are pushing `impl Trait` bounds into it
+    ///
+    /// This function inserts a map that maps the opaque type to that proxy inference var.
+    fn insert_atpit_coercion_table<'b>(&mut self, tys: impl Iterator<Item = &'b Ty>) {
+        struct OpaqueTyCollector<'a, 'b> {
+            table: &'b mut InferenceTable<'a>,
+            opaque_tys: FxHashMap<OpaqueTyId, Ty>,
+        }
+
+        impl<'a, 'b> TypeVisitor<Interner> for OpaqueTyCollector<'a, 'b> {
+            type BreakTy = ();
+
+            fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
+                self
+            }
+
+            fn interner(&self) -> Interner {
+                Interner
+            }
+
+            fn visit_ty(
+                &mut self,
+                ty: &chalk_ir::Ty<Interner>,
+                outer_binder: DebruijnIndex,
+            ) -> std::ops::ControlFlow<Self::BreakTy> {
+                let ty = self.table.resolve_ty_shallow(ty);
+
+                if let TyKind::OpaqueType(id, _) = ty.kind(Interner) {
+                    self.opaque_tys.insert(*id, ty.clone());
+                }
+
+                ty.super_visit_with(self, outer_binder)
+            }
+        }
+
+        // Early return if this is not happening inside the impl block
+        let impl_id = if let Some(impl_id) = self.resolver.impl_def() {
+            impl_id
+        } else {
+            return;
+        };
+
+        let assoc_tys: FxHashSet<_> = self
+            .db
+            .impl_data(impl_id)
+            .items
+            .iter()
+            .filter_map(|item| match item {
+                AssocItemId::TypeAliasId(alias) => Some(*alias),
+                _ => None,
+            })
+            .collect();
+        if assoc_tys.is_empty() {
+            return;
+        }
+
+        let mut collector =
+            OpaqueTyCollector { table: &mut self.table, opaque_tys: FxHashMap::default() };
+        for ty in tys {
+            ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST);
+        }
+        let atpit_coercion_table: FxHashMap<_, _> = collector
+            .opaque_tys
+            .into_iter()
+            .filter_map(|(opaque_ty_id, ty)| {
+                if let ImplTraitId::AssociatedTypeImplTrait(alias_id, _) =
+                    self.db.lookup_intern_impl_trait_id(opaque_ty_id.into())
+                {
+                    if assoc_tys.contains(&alias_id) {
+                        let atpits = self
+                            .db
+                            .type_alias_impl_traits(alias_id)
+                            .expect("Marked as ATPIT but no impl traits!");
+                        let alias_placeholders = TyBuilder::placeholder_subst(self.db, alias_id);
+                        let ty = self.insert_inference_vars_for_impl_trait(
+                            ty,
+                            atpits,
+                            alias_placeholders,
+                        );
+                        return Some((opaque_ty_id, ty));
+                    }
+                }
+
+                None
+            })
+            .collect();
+
+        if !atpit_coercion_table.is_empty() {
+            self.table.atpit_coercion_table = Some(atpit_coercion_table);
+        }
+    }
+
     fn infer_body(&mut self) {
         match self.return_coercion {
             Some(_) => self.infer_return(self.body.body_expr),
@@ -918,6 +1037,12 @@ impl<'a> InferenceContext<'a> {
         self.result.standard_types.unknown.clone()
     }
 
+    fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
+        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
+        let lt = ctx.lower_lifetime(lifetime_ref);
+        self.insert_type_vars(lt)
+    }
+
     /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it.
     fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
         self.table.insert_type_vars_shallow(ty)
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 ff6de61ba64..cfbbc9dd6c0 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
@@ -276,6 +276,23 @@ impl InferenceTable<'_> {
             return success(simple(Adjust::NeverToAny)(to_ty.clone()), to_ty.clone(), vec![]);
         }
 
+        // If we are coercing into an ATPIT, coerce into its proxy inference var, instead.
+        let mut to_ty = to_ty;
+        let _to;
+        if let Some(atpit_table) = &self.atpit_coercion_table {
+            if let TyKind::OpaqueType(opaque_ty_id, _) = to_ty.kind(Interner) {
+                if !matches!(
+                    from_ty.kind(Interner),
+                    TyKind::InferenceVar(..) | TyKind::OpaqueType(..)
+                ) {
+                    if let Some(ty) = atpit_table.get(opaque_ty_id) {
+                        _to = ty.clone();
+                        to_ty = &_to;
+                    }
+                }
+            }
+        }
+
         // Consider coercing the subtype to a DST
         if let Ok(ret) = self.try_coerce_unsized(&from_ty, to_ty) {
             return Ok(ret);
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 a3dab1fd9d5..35d59679355 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
@@ -8,13 +8,12 @@ use std::{
 use chalk_ir::{cast::Cast, fold::Shift, DebruijnIndex, Mutability, TyVariableKind};
 use either::Either;
 use hir_def::{
-    generics::TypeOrConstParamData,
     hir::{
         ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
     },
     lang_item::{LangItem, LangItemTarget},
-    path::{GenericArg, GenericArgs, Path},
-    BlockId, ConstParamId, FieldId, ItemContainerId, Lookup, TupleFieldId, TupleId,
+    path::{GenericArgs, Path},
+    BlockId, FieldId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId,
 };
 use hir_expand::name::{name, Name};
 use stdx::always;
@@ -1816,10 +1815,17 @@ impl InferenceContext<'_> {
         def_generics: Generics,
         generic_args: Option<&GenericArgs>,
     ) -> Substitution {
-        let (parent_params, self_params, type_params, const_params, impl_trait_params) =
-            def_generics.provenance_split();
+        let (
+            parent_params,
+            self_params,
+            type_params,
+            const_params,
+            impl_trait_params,
+            lifetime_params,
+        ) = def_generics.provenance_split();
         assert_eq!(self_params, 0); // method shouldn't have another Self param
-        let total_len = parent_params + type_params + const_params + impl_trait_params;
+        let total_len =
+            parent_params + type_params + const_params + impl_trait_params + lifetime_params;
         let mut substs = Vec::with_capacity(total_len);
 
         // handle provided arguments
@@ -1828,8 +1834,7 @@ impl InferenceContext<'_> {
             for (arg, kind_id) in generic_args
                 .args
                 .iter()
-                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
-                .take(type_params + const_params)
+                .take(type_params + const_params + lifetime_params)
                 .zip(def_generics.iter_id())
             {
                 if let Some(g) = generic_arg_to_chalk(
@@ -1850,6 +1855,7 @@ impl InferenceContext<'_> {
                             DebruijnIndex::INNERMOST,
                         )
                     },
+                    |this, lt_ref| this.make_lifetime(lt_ref),
                 ) {
                     substs.push(g);
                 }
@@ -1858,16 +1864,17 @@ impl InferenceContext<'_> {
 
         // Handle everything else as unknown. This also handles generic arguments for the method's
         // parent (impl or trait), which should come after those for the method.
-        for (id, data) in def_generics.iter().skip(substs.len()) {
-            match data {
-                TypeOrConstParamData::TypeParamData(_) => {
+        for (id, _data) in def_generics.iter().skip(substs.len()) {
+            match id {
+                GenericParamId::TypeParamId(_) => {
                     substs.push(self.table.new_type_var().cast(Interner))
                 }
-                TypeOrConstParamData::ConstParamData(_) => substs.push(
-                    self.table
-                        .new_const_var(self.db.const_param_ty(ConstParamId::from_unchecked(id)))
-                        .cast(Interner),
-                ),
+                GenericParamId::ConstParamId(id) => {
+                    substs.push(self.table.new_const_var(self.db.const_param_ty(id)).cast(Interner))
+                }
+                GenericParamId::LifetimeParamId(_) => {
+                    substs.push(self.table.new_lifetime_var().cast(Interner))
+                }
             }
         }
         assert_eq!(substs.len(), total_len);
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 8f537bb448b..9a1835b625b 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
@@ -11,15 +11,15 @@ use stdx::never;
 
 use crate::{
     builder::ParamKind,
-    consteval,
+    consteval, error_lifetime,
     method_resolution::{self, VisibleFromModule},
     to_chalk_trait_id,
     utils::generics,
-    InferenceDiagnostic, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
-    ValueTyDefId,
+    InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
+    TyKind, ValueTyDefId,
 };
 
-use super::{ExprOrPatId, InferenceContext, TraitRef};
+use super::{ExprOrPatId, InferenceContext};
 
 impl InferenceContext<'_> {
     pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty> {
@@ -111,6 +111,7 @@ impl InferenceContext<'_> {
                 it.next().unwrap_or_else(|| match x {
                     ParamKind::Type => self.result.standard_types.unknown.clone().cast(Interner),
                     ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
+                    ParamKind::Lifetime => error_lifetime().cast(Interner),
                 })
             })
             .build();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index be7547f9bae..afb89fe1e5b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -10,16 +10,18 @@ use chalk_solve::infer::ParameterEnaVariableExt;
 use either::Either;
 use ena::unify::UnifyKey;
 use hir_expand::name;
+use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
 use triomphe::Arc;
 
 use super::{InferOk, InferResult, InferenceContext, TypeError};
 use crate::{
-    consteval::unknown_const, db::HirDatabase, fold_tys_and_consts, static_lifetime,
-    to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue,
-    DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData, Guidance, InEnvironment,
-    InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution,
-    Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause,
+    consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts,
+    static_lifetime, to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical,
+    Const, ConstValue, DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData,
+    Guidance, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, ProjectionTy,
+    ProjectionTyExt, Scalar, Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
+    TyKind, VariableKind, WhereClause,
 };
 
 impl InferenceContext<'_> {
@@ -239,6 +241,7 @@ type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
 pub(crate) struct InferenceTable<'a> {
     pub(crate) db: &'a dyn HirDatabase,
     pub(crate) trait_env: Arc<TraitEnvironment>,
+    pub(crate) atpit_coercion_table: Option<FxHashMap<OpaqueTyId, Ty>>,
     var_unification_table: ChalkInferenceTable,
     type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
     pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
@@ -258,6 +261,7 @@ impl<'a> InferenceTable<'a> {
         InferenceTable {
             db,
             trait_env,
+            atpit_coercion_table: None,
             var_unification_table: ChalkInferenceTable::new(),
             type_variable_table: SmallVec::new(),
             pending_obligations: Vec::new(),
@@ -803,6 +807,7 @@ impl<'a> InferenceTable<'a> {
             .fill(|it| {
                 let arg = match it {
                     ParamKind::Type => self.new_type_var(),
+                    ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"),
                     ParamKind::Const(_) => unreachable!("Tuple with const parameter"),
                 };
                 arg_tys.push(arg.clone());
@@ -857,11 +862,16 @@ impl<'a> InferenceTable<'a> {
     where
         T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
     {
-        fold_tys_and_consts(
+        fold_generic_args(
             ty,
-            |it, _| match it {
-                Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)),
-                Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)),
+            |arg, _| match arg {
+                GenericArgData::Ty(ty) => GenericArgData::Ty(self.insert_type_vars_shallow(ty)),
+                // FIXME: insert lifetime vars once LifetimeData::InferenceVar
+                // and specific error variant for lifetimes start being constructed
+                GenericArgData::Lifetime(lt) => GenericArgData::Lifetime(lt),
+                GenericArgData::Const(c) => {
+                    GenericArgData::Const(self.insert_const_vars_shallow(c))
+                }
             },
             DebruijnIndex::INNERMOST,
         )
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 9655981cc9c..dd949e26c2a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -389,6 +389,9 @@ pub fn layout_of_ty_query(
                     let infer = db.infer(func.into());
                     return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env);
                 }
+                crate::ImplTraitId::AssociatedTypeImplTrait(..) => {
+                    return Err(LayoutError::NotImplemented);
+                }
                 crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
                     return Err(LayoutError::NotImplemented)
                 }
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 ec97bdc2c43..ba64f5c8d7e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -15,7 +15,8 @@ extern crate rustc_abi;
 #[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_abi as rustc_abi;
 
-// No need to use the in-tree one.
+// Use the crates.io version unconditionally until the API settles enough that we can switch to
+// using the in-tree one.
 extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis;
 
 mod builder;
@@ -89,8 +90,8 @@ pub use lower::{
 };
 pub use mapping::{
     from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
-    lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id,
-    to_placeholder_idx,
+    lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
+    to_foreign_def_id, to_placeholder_idx,
 };
 pub use method_resolution::check_orphan_rules;
 pub use traits::TraitEnvironment;
@@ -334,11 +335,23 @@ pub(crate) fn make_binders_with_count<T: HasInterner<Interner = Interner>>(
     generics: &Generics,
     value: T,
 ) -> Binders<T> {
-    let it = generics.iter_id().take(count).map(|id| match id {
-        Either::Left(_) => None,
-        Either::Right(id) => Some(db.const_param_ty(id)),
-    });
-    crate::make_type_and_const_binders(it, value)
+    let it = generics.iter_id().take(count);
+
+    Binders::new(
+        VariableKinds::from_iter(
+            Interner,
+            it.map(|x| match x {
+                hir_def::GenericParamId::ConstParamId(id) => {
+                    chalk_ir::VariableKind::Const(db.const_param_ty(id))
+                }
+                hir_def::GenericParamId::TypeParamId(_) => {
+                    chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
+                }
+                hir_def::GenericParamId::LifetimeParamId(_) => chalk_ir::VariableKind::Lifetime,
+            }),
+        ),
+        value,
+    )
 }
 
 pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
@@ -584,29 +597,34 @@ impl TypeFoldable<Interner> for CallableSig {
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 pub enum ImplTraitId {
-    ReturnTypeImplTrait(hir_def::FunctionId, RpitId),
+    ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx),
+    AssociatedTypeImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
     AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
 }
 impl_intern_value_trivial!(ImplTraitId);
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct ReturnTypeImplTraits {
-    pub(crate) impl_traits: Arena<ReturnTypeImplTrait>,
+pub struct ImplTraits {
+    pub(crate) impl_traits: Arena<ImplTrait>,
 }
 
-has_interner!(ReturnTypeImplTraits);
+has_interner!(ImplTraits);
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct ReturnTypeImplTrait {
+pub struct ImplTrait {
     pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
 }
 
-pub type RpitId = Idx<ReturnTypeImplTrait>;
+pub type ImplTraitIdx = Idx<ImplTrait>;
 
 pub fn static_lifetime() -> Lifetime {
     LifetimeData::Static.intern(Interner)
 }
 
+pub fn error_lifetime() -> Lifetime {
+    static_lifetime()
+}
+
 pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
     t: T,
     for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
@@ -696,6 +714,55 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold
     t.fold_with(&mut TyFolder(f), binders)
 }
 
+pub(crate) fn fold_generic_args<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
+    t: T,
+    f: impl FnMut(GenericArgData, DebruijnIndex) -> GenericArgData,
+    binders: DebruijnIndex,
+) -> T {
+    use chalk_ir::fold::{TypeFolder, TypeSuperFoldable};
+    #[derive(chalk_derive::FallibleTypeFolder)]
+    #[has_interner(Interner)]
+    struct TyFolder<F: FnMut(GenericArgData, DebruijnIndex) -> GenericArgData>(F);
+    impl<F: FnMut(GenericArgData, DebruijnIndex) -> GenericArgData> TypeFolder<Interner>
+        for TyFolder<F>
+    {
+        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
+            self
+        }
+
+        fn interner(&self) -> Interner {
+            Interner
+        }
+
+        fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
+            let ty = ty.super_fold_with(self.as_dyn(), outer_binder);
+            self.0(GenericArgData::Ty(ty), outer_binder)
+                .intern(Interner)
+                .ty(Interner)
+                .unwrap()
+                .clone()
+        }
+
+        fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const {
+            self.0(GenericArgData::Const(c), outer_binder)
+                .intern(Interner)
+                .constant(Interner)
+                .unwrap()
+                .clone()
+        }
+
+        fn fold_lifetime(&mut self, lt: Lifetime, outer_binder: DebruijnIndex) -> Lifetime {
+            let lt = lt.super_fold_with(self.as_dyn(), outer_binder);
+            self.0(GenericArgData::Lifetime(lt), outer_binder)
+                .intern(Interner)
+                .lifetime(Interner)
+                .unwrap()
+                .clone()
+        }
+    }
+    t.fold_with(&mut TyFolder(f), binders)
+}
+
 /// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
 /// ensures there are no unbound variables or inference variables anywhere in
 /// the `t`.
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 dac20f22597..25ccc84c13c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -24,17 +24,20 @@ use hir_def::{
     data::adt::StructKind,
     expander::Expander,
     generics::{
-        TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
+        GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
+        WherePredicateTypeTarget,
     },
     lang_item::LangItem,
     nameres::MacroSubNs,
     path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
-    resolver::{HasResolver, Resolver, TypeNs},
-    type_ref::{ConstRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
+    resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
+    type_ref::{
+        ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
+    },
     AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
-    GenericDefId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, LocalFieldId, Lookup,
-    ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId,
-    TypeParamId, UnionId, VariantId,
+    GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, LocalFieldId,
+    Lookup, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId,
+    UnionId, VariantId,
 };
 use hir_expand::{name::Name, ExpandResult};
 use intern::Interned;
@@ -52,18 +55,18 @@ use crate::{
         unknown_const_as_generic,
     },
     db::HirDatabase,
-    make_binders,
-    mapping::{from_chalk_trait_id, ToChalk},
+    error_lifetime, 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::Generics,
     utils::{
-        all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
+        all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics,
         InTypeConstIdMetadata,
     },
     AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy,
-    FnAbi, FnPointer, FnSig, FnSubst, ImplTraitId, Interner, ParamKind, PolyFnSig, ProjectionTy,
-    QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits,
-    Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
+    FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
+    LifetimeData, ParamKind, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
+    QuantifiedWhereClauses, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder,
+    TyKind, WhereClause,
 };
 
 #[derive(Debug)]
@@ -76,7 +79,7 @@ enum ImplTraitLoweringState {
     /// we're grouping the mutable data (the counter and this field) together
     /// with the immutable context (the references to the DB and resolver).
     /// Splitting this up would be a possible fix.
-    Opaque(RefCell<Arena<ReturnTypeImplTrait>>),
+    Opaque(RefCell<Arena<ImplTrait>>),
     Param(Cell<u16>),
     Variable(Cell<u16>),
     Disallowed,
@@ -275,9 +278,11 @@ impl<'a> TyLoweringContext<'a> {
                 let inner_ty = self.lower_ty(inner);
                 TyKind::Slice(inner_ty).intern(Interner)
             }
-            TypeRef::Reference(inner, _, mutability) => {
+            TypeRef::Reference(inner, lifetime, mutability) => {
                 let inner_ty = self.lower_ty(inner);
-                let lifetime = static_lifetime();
+                // FIXME: It should infer the eldided lifetimes instead of stubbing with static
+                let lifetime =
+                    lifetime.as_ref().map_or_else(static_lifetime, |lr| self.lower_lifetime(lr));
                 TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty)
                     .intern(Interner)
             }
@@ -301,15 +306,18 @@ impl<'a> TyLoweringContext<'a> {
             TypeRef::ImplTrait(bounds) => {
                 match &self.impl_trait_mode {
                     ImplTraitLoweringState::Opaque(opaque_type_data) => {
-                        let func = match self.resolver.generic_def() {
-                            Some(GenericDefId::FunctionId(f)) => f,
-                            _ => panic!("opaque impl trait lowering in non-function"),
+                        let origin = match self.resolver.generic_def() {
+                            Some(GenericDefId::FunctionId(it)) => Either::Left(it),
+                            Some(GenericDefId::TypeAliasId(it)) => Either::Right(it),
+                            _ => panic!(
+                                "opaque impl trait lowering must be in function or type alias"
+                            ),
                         };
 
                         // this dance is to make sure the data is in the right
                         // place even if we encounter more opaque types while
                         // lowering the bounds
-                        let idx = opaque_type_data.borrow_mut().alloc(ReturnTypeImplTrait {
+                        let idx = opaque_type_data.borrow_mut().alloc(ImplTrait {
                             bounds: crate::make_single_type_binders(Vec::new()),
                         });
                         // We don't want to lower the bounds inside the binders
@@ -323,13 +331,17 @@ impl<'a> TyLoweringContext<'a> {
                         // away instead of two.
                         let actual_opaque_type_data = self
                             .with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
-                                ctx.lower_impl_trait(bounds, func)
+                                ctx.lower_impl_trait(bounds, self.resolver.krate())
                             });
                         opaque_type_data.borrow_mut()[idx] = actual_opaque_type_data;
 
-                        let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
+                        let impl_trait_id = origin.either(
+                            |f| ImplTraitId::ReturnTypeImplTrait(f, idx),
+                            |a| ImplTraitId::AssociatedTypeImplTrait(a, idx),
+                        );
                         let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
-                        let generics = generics(self.db.upcast(), func.into());
+                        let generics =
+                            generics(self.db.upcast(), origin.either(|f| f.into(), |a| a.into()));
                         let parameters = generics.bound_vars_subst(self.db, self.in_binders);
                         TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
                     }
@@ -344,13 +356,18 @@ impl<'a> TyLoweringContext<'a> {
                                 .filter(|(_, data)| {
                                     matches!(
                                         data,
-                                        TypeOrConstParamData::TypeParamData(data)
+                                        GenericParamDataRef::TypeParamData(data)
                                         if data.provenance == TypeParamProvenance::ArgumentImplTrait
                                     )
                                 })
                                 .nth(idx as usize)
                                 .map_or(TyKind::Error, |(id, _)| {
-                                    TyKind::Placeholder(to_placeholder_idx(self.db, id))
+                                    if let GenericParamId::TypeParamId(id) = id {
+                                        TyKind::Placeholder(to_placeholder_idx(self.db, id.into()))
+                                    } else {
+                                        // we just filtered them out
+                                        unreachable!("Unexpected lifetime or const argument");
+                                    }
                                 });
                             param.intern(Interner)
                         } else {
@@ -367,11 +384,12 @@ impl<'a> TyLoweringContext<'a> {
                             list_params,
                             const_params,
                             _impl_trait_params,
+                            _lifetime_params,
                         ) = if let Some(def) = self.resolver.generic_def() {
                             let generics = generics(self.db.upcast(), def);
                             generics.provenance_split()
                         } else {
-                            (0, 0, 0, 0, 0)
+                            (0, 0, 0, 0, 0, 0)
                         };
                         TyKind::BoundVar(BoundVar::new(
                             self.in_binders,
@@ -808,9 +826,16 @@ impl<'a> TyLoweringContext<'a> {
             return Substitution::empty(Interner);
         };
         let def_generics = generics(self.db.upcast(), def);
-        let (parent_params, self_params, type_params, const_params, impl_trait_params) =
-            def_generics.provenance_split();
-        let item_len = self_params + type_params + const_params + impl_trait_params;
+        let (
+            parent_params,
+            self_params,
+            type_params,
+            const_params,
+            impl_trait_params,
+            lifetime_params,
+        ) = def_generics.provenance_split();
+        let item_len =
+            self_params + type_params + const_params + impl_trait_params + lifetime_params;
         let total_len = parent_params + item_len;
 
         let ty_error = TyKind::Error.intern(Interner).cast(Interner);
@@ -825,7 +850,10 @@ impl<'a> TyLoweringContext<'a> {
                 .take(self_params)
             {
                 if let Some(id) = def_generic_iter.next() {
-                    assert!(id.is_left());
+                    assert!(matches!(
+                        id,
+                        GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_)
+                    ));
                     substs.push(x);
                 }
             }
@@ -858,6 +886,7 @@ impl<'a> TyLoweringContext<'a> {
                         &mut (),
                         |_, type_ref| self.lower_ty(type_ref),
                         |_, const_ref, ty| self.lower_const(const_ref, ty),
+                        |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
                     ) {
                         had_explicit_args = true;
                         substs.push(x);
@@ -867,15 +896,45 @@ impl<'a> TyLoweringContext<'a> {
                     }
                 }
             }
+
+            for arg in generic_args
+                .args
+                .iter()
+                .filter(|arg| matches!(arg, GenericArg::Lifetime(_)))
+                .take(lifetime_params)
+            {
+                // Taking into the fact that def_generic_iter will always have lifetimes at the end
+                // Should have some test cases tho to test this behaviour more properly
+                if let Some(id) = def_generic_iter.next() {
+                    if let Some(x) = generic_arg_to_chalk(
+                        self.db,
+                        id,
+                        arg,
+                        &mut (),
+                        |_, type_ref| self.lower_ty(type_ref),
+                        |_, const_ref, ty| self.lower_const(const_ref, ty),
+                        |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
+                    ) {
+                        had_explicit_args = true;
+                        substs.push(x);
+                    } else {
+                        // Never return a None explicitly
+                        never!("Unexpected None by generic_arg_to_chalk");
+                    }
+                }
+            }
         } else {
             fill_self_params();
         }
 
         // These params include those of parent.
         let remaining_params: SmallVec<[_; 2]> = def_generic_iter
-            .map(|eid| match eid {
-                Either::Left(_) => ty_error.clone(),
-                Either::Right(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
+            .map(|id| match id {
+                GenericParamId::ConstParamId(x) => {
+                    unknown_const_as_generic(self.db.const_param_ty(x))
+                }
+                GenericParamId::TypeParamId(_) => ty_error.clone(),
+                GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
             })
             .collect();
         assert_eq!(remaining_params.len() + substs.len(), total_len);
@@ -1107,8 +1166,12 @@ impl<'a> TyLoweringContext<'a> {
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
                 );
                 if let Some(type_ref) = &binding.type_ref {
-                    if let (TypeRef::ImplTrait(bounds), ImplTraitLoweringState::Disallowed) =
-                        (type_ref, &self.impl_trait_mode)
+                    if let (
+                        TypeRef::ImplTrait(bounds),
+                        ImplTraitLoweringState::Param(_)
+                        | ImplTraitLoweringState::Variable(_)
+                        | ImplTraitLoweringState::Disallowed,
+                    ) = (type_ref, &self.impl_trait_mode)
                     {
                         for bound in bounds {
                             predicates.extend(
@@ -1270,11 +1333,7 @@ impl<'a> TyLoweringContext<'a> {
         }
     }
 
-    fn lower_impl_trait(
-        &self,
-        bounds: &[Interned<TypeBound>],
-        func: FunctionId,
-    ) -> ReturnTypeImplTrait {
+    fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>], krate: CrateId) -> ImplTrait {
         cov_mark::hit!(lower_rpit);
         let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
         let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
@@ -1284,7 +1343,6 @@ impl<'a> TyLoweringContext<'a> {
                 .collect();
 
             if !ctx.unsized_types.borrow().contains(&self_ty) {
-                let krate = func.krate(ctx.db.upcast());
                 let sized_trait = ctx
                     .db
                     .lang_item(krate, LangItem::Sized)
@@ -1301,7 +1359,34 @@ impl<'a> TyLoweringContext<'a> {
             }
             predicates
         });
-        ReturnTypeImplTrait { bounds: crate::make_single_type_binders(predicates) }
+        ImplTrait { bounds: crate::make_single_type_binders(predicates) }
+    }
+
+    pub fn lower_lifetime(&self, lifetime: &LifetimeRef) -> Lifetime {
+        match self.resolver.resolve_lifetime(lifetime) {
+            Some(resolution) => match resolution {
+                LifetimeNs::Static => static_lifetime(),
+                LifetimeNs::LifetimeParam(id) => match self.type_param_mode {
+                    ParamLoweringMode::Placeholder => {
+                        LifetimeData::Placeholder(lt_to_placeholder_idx(self.db, id))
+                    }
+                    ParamLoweringMode::Variable => {
+                        let generics = generics(
+                            self.db.upcast(),
+                            self.resolver.generic_def().expect("generics in scope"),
+                        );
+                        let idx = match generics.lifetime_idx(id) {
+                            None => return error_lifetime(),
+                            Some(idx) => idx,
+                        };
+
+                        LifetimeData::BoundVar(BoundVar::new(self.in_binders, idx))
+                    }
+                }
+                .intern(Interner),
+            },
+            None => error_lifetime(),
+        }
     }
 }
 
@@ -1685,7 +1770,7 @@ pub(crate) fn generic_defaults_query(
 
     let defaults = Arc::from_iter(generic_params.iter().enumerate().map(|(idx, (id, p))| {
         match p {
-            TypeOrConstParamData::TypeParamData(p) => {
+            GenericParamDataRef::TypeParamData(p) => {
                 let mut ty =
                     p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
                 // Each default can only refer to previous parameters.
@@ -1694,13 +1779,13 @@ pub(crate) fn generic_defaults_query(
                 ty = fallback_bound_vars(ty, idx, parent_start_idx);
                 crate::make_binders(db, &generic_params, ty.cast(Interner))
             }
-            TypeOrConstParamData::ConstParamData(p) => {
+            GenericParamDataRef::ConstParamData(p) => {
+                let GenericParamId::ConstParamId(id) = id else {
+                    unreachable!("Unexpected lifetime or type argument")
+                };
+
                 let mut val = p.default.as_ref().map_or_else(
-                    || {
-                        unknown_const_as_generic(
-                            db.const_param_ty(ConstParamId::from_unchecked(id)),
-                        )
-                    },
+                    || unknown_const_as_generic(db.const_param_ty(id)),
                     |c| {
                         let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
                         c.cast(Interner)
@@ -1710,6 +1795,10 @@ pub(crate) fn generic_defaults_query(
                 val = fallback_bound_vars(val, idx, parent_start_idx);
                 make_binders(db, &generic_params, val)
             }
+            GenericParamDataRef::LifetimeParamData(_) => {
+                // using static because it requires defaults
+                make_binders(db, &generic_params, static_lifetime().cast(Interner))
+            }
         }
     }));
 
@@ -1726,8 +1815,9 @@ pub(crate) fn generic_defaults_recover(
     // we still need one default per parameter
     let defaults = Arc::from_iter(generic_params.iter_id().map(|id| {
         let val = match id {
-            Either::Left(_) => TyKind::Error.intern(Interner).cast(Interner),
-            Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
+            GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
+            GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)),
+            GenericParamId::LifetimeParamId(_) => static_lifetime().cast(Interner),
         };
         crate::make_binders(db, &generic_params, val)
     }));
@@ -1869,6 +1959,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
     let generics = generics(db.upcast(), t.into());
     let resolver = t.resolver(db.upcast());
     let ctx = TyLoweringContext::new(db, &resolver, t.into())
+        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
     let type_alias_data = db.type_alias_data(t);
     if type_alias_data.is_extern {
@@ -2029,7 +2120,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
 pub(crate) fn return_type_impl_traits(
     db: &dyn HirDatabase,
     def: hir_def::FunctionId,
-) -> Option<Arc<Binders<ReturnTypeImplTraits>>> {
+) -> Option<Arc<Binders<ImplTraits>>> {
     // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
     let data = db.function_data(def);
     let resolver = def.resolver(db.upcast());
@@ -2038,7 +2129,7 @@ pub(crate) fn return_type_impl_traits(
         .with_type_param_mode(ParamLoweringMode::Variable);
     let _ret = ctx_ret.lower_ty(&data.ret_type);
     let generics = generics(db.upcast(), def.into());
-    let return_type_impl_traits = ReturnTypeImplTraits {
+    let return_type_impl_traits = ImplTraits {
         impl_traits: match ctx_ret.impl_trait_mode {
             ImplTraitLoweringState::Opaque(x) => x.into_inner(),
             _ => unreachable!(),
@@ -2051,6 +2142,32 @@ pub(crate) fn return_type_impl_traits(
     }
 }
 
+pub(crate) fn type_alias_impl_traits(
+    db: &dyn HirDatabase,
+    def: hir_def::TypeAliasId,
+) -> Option<Arc<Binders<ImplTraits>>> {
+    let data = db.type_alias_data(def);
+    let resolver = def.resolver(db.upcast());
+    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
+        .with_type_param_mode(ParamLoweringMode::Variable);
+    if let Some(type_ref) = &data.type_ref {
+        let _ty = ctx.lower_ty(type_ref);
+    }
+    let generics = generics(db.upcast(), def.into());
+    let type_alias_impl_traits = ImplTraits {
+        impl_traits: match ctx.impl_trait_mode {
+            ImplTraitLoweringState::Opaque(x) => x.into_inner(),
+            _ => unreachable!(),
+        },
+    };
+    if type_alias_impl_traits.impl_traits.is_empty() {
+        None
+    } else {
+        Some(Arc::new(make_binders(db, &generics, type_alias_impl_traits)))
+    }
+}
+
 pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
     match m {
         hir_def::type_ref::Mutability::Shared => Mutability::Not,
@@ -2064,23 +2181,29 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
 /// Returns `Some` of the lowered generic arg. `None` if the provided arg is a lifetime.
 pub(crate) fn generic_arg_to_chalk<'a, T>(
     db: &dyn HirDatabase,
-    kind_id: Either<TypeParamId, ConstParamId>,
+    kind_id: GenericParamId,
     arg: &'a GenericArg,
     this: &mut T,
     for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
     for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a,
+    for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a,
 ) -> Option<crate::GenericArg> {
     let kind = match kind_id {
-        Either::Left(_) => ParamKind::Type,
-        Either::Right(id) => {
+        GenericParamId::TypeParamId(_) => ParamKind::Type,
+        GenericParamId::ConstParamId(id) => {
             let ty = db.const_param_ty(id);
             ParamKind::Const(ty)
         }
+        GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
     };
     Some(match (arg, kind) {
         (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner),
         (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
+        (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
+            for_lifetime(this, lifetime_ref).cast(Interner)
+        }
         (GenericArg::Const(_), ParamKind::Type) => TyKind::Error.intern(Interner).cast(Interner),
+        (GenericArg::Lifetime(_), ParamKind::Type) => TyKind::Error.intern(Interner).cast(Interner),
         (GenericArg::Type(t), ParamKind::Const(c_ty)) => {
             // We want to recover simple idents, which parser detects them
             // as types. Maybe here is not the best place to do it, but
@@ -2096,7 +2219,9 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
             }
             unknown_const_as_generic(c_ty)
         }
-        (GenericArg::Lifetime(_), _) => return None,
+        (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => unknown_const_as_generic(c_ty),
+        (GenericArg::Type(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
+        (GenericArg::Const(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
     })
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
index fba760974f2..c61d8277142 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
@@ -151,6 +151,14 @@ pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> L
     db.lookup_intern_lifetime_param_id(interned_id)
 }
 
+pub fn lt_to_placeholder_idx(db: &dyn HirDatabase, id: LifetimeParamId) -> PlaceholderIndex {
+    let interned_id = db.intern_lifetime_param_id(id);
+    PlaceholderIndex {
+        ui: chalk_ir::UniverseIndex::ROOT,
+        idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(),
+    }
+}
+
 pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
     chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id))
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index a679a114b4b..73b07df56f7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -4,7 +4,7 @@
 //! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs.
 use std::ops::ControlFlow;
 
-use base_db::{CrateId, Edition};
+use base_db::CrateId;
 use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause};
 use hir_def::{
     data::{adt::StructFlags, ImplData},
@@ -15,6 +15,7 @@ use hir_def::{
 use hir_expand::name::Name;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::{smallvec, SmallVec};
+use span::Edition;
 use stdx::never;
 use triomphe::Arc;
 
@@ -643,7 +644,7 @@ pub fn is_dyn_method(
     let ItemContainerId::TraitId(trait_id) = func.lookup(db.upcast()).container else {
         return None;
     };
-    let trait_params = db.generic_params(trait_id.into()).type_or_consts.len();
+    let trait_params = db.generic_params(trait_id.into()).len();
     let fn_params = fn_subst.len(Interner) - trait_params;
     let trait_ref = TraitRef {
         trait_id: to_chalk_trait_id(trait_id),
@@ -685,7 +686,7 @@ pub(crate) fn lookup_impl_method_query(
     let ItemContainerId::TraitId(trait_id) = func.lookup(db.upcast()).container else {
         return (func, fn_subst);
     };
-    let trait_params = db.generic_params(trait_id.into()).type_or_consts.len();
+    let trait_params = db.generic_params(trait_id.into()).len();
     let fn_params = fn_subst.len(Interner) - trait_params;
     let trait_ref = TraitRef {
         trait_id: to_chalk_trait_id(trait_id),
@@ -966,7 +967,7 @@ pub fn iterate_method_candidates_dyn(
             // the methods by autoderef order of *receiver types*, not *self
             // types*.
 
-            let mut table = InferenceTable::new(db, env.clone());
+            let mut table = InferenceTable::new(db, env);
             let ty = table.instantiate_canonical(ty.clone());
             let deref_chain = autoderef_method_receiver(&mut table, ty);
 
@@ -1044,7 +1045,7 @@ fn iterate_method_candidates_with_autoref(
     let ref_muted = Canonical {
         value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone())
             .intern(Interner),
-        binders: receiver_ty.binders.clone(),
+        binders: receiver_ty.binders,
     };
 
     iterate_method_candidates_by_receiver(ref_muted, first_adjustment.with_autoref(Mutability::Mut))
@@ -1060,7 +1061,7 @@ fn iterate_method_candidates_by_receiver(
     name: Option<&Name>,
     mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
-    let receiver_ty = table.instantiate_canonical(receiver_ty.clone());
+    let receiver_ty = table.instantiate_canonical(receiver_ty);
     // We're looking for methods with *receiver* type receiver_ty. These could
     // be found in any of the derefs of receiver_ty, so we have to go through
     // that, including raw derefs.
@@ -1456,7 +1457,7 @@ fn is_valid_trait_method_candidate(
                 if let Some(receiver_ty) = receiver_ty {
                     check_that!(data.has_self_param());
 
-                    let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
+                    let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst))
                         .fill_with_inference_vars(table)
                         .build();
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index fd98141af63..045ffb418c8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -1931,7 +1931,11 @@ impl Evaluator<'_> {
             ty: &Ty,
             locals: &Locals,
             mm: &mut ComplexMemoryMap,
+            stack_depth_limit: usize,
         ) -> Result<()> {
+            if stack_depth_limit.checked_sub(1).is_none() {
+                return Err(MirEvalError::StackOverflow);
+            }
             match ty.kind(Interner) {
                 TyKind::Ref(_, _, t) => {
                     let size = this.size_align_of(t, locals)?;
@@ -1970,7 +1974,14 @@ impl Evaluator<'_> {
                             if let Some(ty) = check_inner {
                                 for i in 0..count {
                                     let offset = element_size * i;
-                                    rec(this, &b[offset..offset + element_size], ty, locals, mm)?;
+                                    rec(
+                                        this,
+                                        &b[offset..offset + element_size],
+                                        ty,
+                                        locals,
+                                        mm,
+                                        stack_depth_limit - 1,
+                                    )?;
                                 }
                             }
                         }
@@ -1984,7 +1995,14 @@ impl Evaluator<'_> {
                     let size = this.size_of_sized(inner, locals, "inner of array")?;
                     for i in 0..len {
                         let offset = i * size;
-                        rec(this, &bytes[offset..offset + size], inner, locals, mm)?;
+                        rec(
+                            this,
+                            &bytes[offset..offset + size],
+                            inner,
+                            locals,
+                            mm,
+                            stack_depth_limit - 1,
+                        )?;
                     }
                 }
                 chalk_ir::TyKind::Tuple(_, subst) => {
@@ -1993,7 +2011,14 @@ impl Evaluator<'_> {
                         let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument
                         let offset = layout.fields.offset(id).bytes_usize();
                         let size = this.layout(ty)?.size.bytes_usize();
-                        rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
+                        rec(
+                            this,
+                            &bytes[offset..offset + size],
+                            ty,
+                            locals,
+                            mm,
+                            stack_depth_limit - 1,
+                        )?;
                     }
                 }
                 chalk_ir::TyKind::Adt(adt, subst) => match adt.0 {
@@ -2008,7 +2033,14 @@ impl Evaluator<'_> {
                                 .bytes_usize();
                             let ty = &field_types[f].clone().substitute(Interner, subst);
                             let size = this.layout(ty)?.size.bytes_usize();
-                            rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
+                            rec(
+                                this,
+                                &bytes[offset..offset + size],
+                                ty,
+                                locals,
+                                mm,
+                                stack_depth_limit - 1,
+                            )?;
                         }
                     }
                     AdtId::EnumId(e) => {
@@ -2027,7 +2059,14 @@ impl Evaluator<'_> {
                                     l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize();
                                 let ty = &field_types[f].clone().substitute(Interner, subst);
                                 let size = this.layout(ty)?.size.bytes_usize();
-                                rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
+                                rec(
+                                    this,
+                                    &bytes[offset..offset + size],
+                                    ty,
+                                    locals,
+                                    mm,
+                                    stack_depth_limit - 1,
+                                )?;
                             }
                         }
                     }
@@ -2038,7 +2077,7 @@ impl Evaluator<'_> {
             Ok(())
         }
         let mut mm = ComplexMemoryMap::default();
-        rec(self, bytes, ty, locals, &mut mm)?;
+        rec(self, bytes, ty, locals, &mut mm, self.stack_depth_limit - 1)?;
         Ok(mm)
     }
 
@@ -2317,7 +2356,7 @@ impl Evaluator<'_> {
 
     fn exec_fn_with_args(
         &mut self,
-        def: FunctionId,
+        mut def: FunctionId,
         args: &[IntervalAndTy],
         generic_args: Substitution,
         locals: &Locals,
@@ -2335,6 +2374,9 @@ impl Evaluator<'_> {
         )? {
             return Ok(None);
         }
+        if let Some(redirect_def) = self.detect_and_redirect_special_function(def)? {
+            def = redirect_def;
+        }
         let arg_bytes = args.iter().map(|it| IntervalOrOwned::Borrowed(it.interval));
         match self.get_mir_or_dyn_index(def, generic_args.clone(), locals, span)? {
             MirOrDynIndex::Dyn(self_ty_idx) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 628a1fe2d28..d4d669182f2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -13,7 +13,7 @@ use crate::mir::eval::{
     name, pad16, static_lifetime, Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId,
     HasModule, HirDisplay, Interned, InternedClosure, Interner, Interval, IntervalAndTy,
     IntervalOrOwned, ItemContainerId, LangItem, Layout, Locals, Lookup, MirEvalError, MirSpan,
-    ModPath, Mutability, Result, Substitution, Ty, TyBuilder, TyExt,
+    Mutability, Result, Substitution, Ty, TyBuilder, TyExt,
 };
 
 mod simd;
@@ -158,6 +158,25 @@ impl Evaluator<'_> {
         Ok(false)
     }
 
+    pub(super) fn detect_and_redirect_special_function(
+        &mut self,
+        def: FunctionId,
+    ) -> Result<Option<FunctionId>> {
+        // `PanicFmt` is redirected to `ConstPanicFmt`
+        if let Some(LangItem::PanicFmt) = self.db.lang_attr(def.into()) {
+            let resolver =
+                self.db.crate_def_map(self.crate_id).crate_root().resolver(self.db.upcast());
+
+            let Some(hir_def::lang_item::LangItemTarget::Function(const_panic_fmt)) =
+                self.db.lang_item(resolver.krate(), LangItem::ConstPanicFmt)
+            else {
+                not_supported!("const_panic_fmt lang item not found or not a function");
+            };
+            return Ok(Some(const_panic_fmt));
+        }
+        Ok(None)
+    }
+
     /// Clone has special impls for tuples and function pointers
     fn exec_clone(
         &mut self,
@@ -291,9 +310,14 @@ impl Evaluator<'_> {
         use LangItem::*;
         let candidate = self.db.lang_attr(def.into())?;
         // We want to execute these functions with special logic
-        if [PanicFmt, BeginPanic, SliceLen, DropInPlace].contains(&candidate) {
+        // `PanicFmt` is not detected here as it's redirected later.
+        if [BeginPanic, SliceLen, DropInPlace].contains(&candidate) {
             return Some(candidate);
         }
+        if self.db.attrs(def.into()).by_key("rustc_const_panic_str").exists() {
+            // `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE.
+            return Some(LangItem::BeginPanic);
+        }
         None
     }
 
@@ -309,43 +333,6 @@ impl Evaluator<'_> {
         let mut args = args.iter();
         match it {
             BeginPanic => Err(MirEvalError::Panic("<unknown-panic-payload>".to_owned())),
-            PanicFmt => {
-                let message = (|| {
-                    let resolver = self
-                        .db
-                        .crate_def_map(self.crate_id)
-                        .crate_root()
-                        .resolver(self.db.upcast());
-                    let Some(format_fn) = resolver.resolve_path_in_value_ns_fully(
-                        self.db.upcast(),
-                        &hir_def::path::Path::from_known_path_with_no_generic(
-                            ModPath::from_segments(
-                                hir_expand::mod_path::PathKind::Abs,
-                                [name![std], name![fmt], name![format]],
-                            ),
-                        ),
-                    ) else {
-                        not_supported!("std::fmt::format not found");
-                    };
-                    let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else {
-                        not_supported!("std::fmt::format is not a function")
-                    };
-                    let interval = self.interpret_mir(
-                        self.db
-                            .mir_body(format_fn.into())
-                            .map_err(|e| MirEvalError::MirLowerError(format_fn, e))?,
-                        args.map(|x| IntervalOrOwned::Owned(x.clone())),
-                    )?;
-                    let message_string = interval.get(self)?;
-                    let addr =
-                        Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?;
-                    let size = from_bytes!(usize, message_string[2 * self.ptr_size()..]);
-                    Ok(std::string::String::from_utf8_lossy(self.read_memory(addr, size)?)
-                        .into_owned())
-                })()
-                .unwrap_or_else(|e| format!("Failed to render panic format args: {e:?}"));
-                Err(MirEvalError::Panic(message))
-            }
             SliceLen => {
                 let arg = args.next().ok_or(MirEvalError::InternalError(
                     "argument of <[T]>::len() is not provided".into(),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
index d2e413f0a33..d6557c3a816 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
@@ -82,6 +82,9 @@ impl FallibleTypeFolder<Interner> for Filler<'_> {
                         };
                         filler.try_fold_ty(infer.type_of_rpit[idx].clone(), outer_binder)
                     }
+                    crate::ImplTraitId::AssociatedTypeImplTrait(..) => {
+                        not_supported!("associated type impl trait");
+                    }
                     crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
                         not_supported!("async block impl trait");
                     }
@@ -181,8 +184,16 @@ impl Filler<'_> {
                                     self.generics
                                         .as_ref()
                                         .and_then(|it| it.iter().nth(b.index))
-                                        .unwrap()
-                                        .0,
+                                        .and_then(|(id, _)| match id {
+                                            hir_def::GenericParamId::ConstParamId(id) => {
+                                                Some(hir_def::TypeOrConstParamId::from(id))
+                                            }
+                                            hir_def::GenericParamId::TypeParamId(id) => {
+                                                Some(hir_def::TypeOrConstParamId::from(id))
+                                            }
+                                            _ => None,
+                                        })
+                                        .unwrap(),
                                     self.subst.clone(),
                                 )
                             })?
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 d699067b5a6..2a46becbfda 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -298,7 +298,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
             if let Some(syntax_ptr) = body_source_map.self_param_syntax() {
                 let root = db.parse_or_expand(syntax_ptr.file_id);
                 let node = syntax_ptr.map(|ptr| ptr.to_node(&root).syntax().clone());
-                types.push((node.clone(), ty));
+                types.push((node, ty));
             }
         }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
index e75b037e38d..50692674996 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
@@ -85,7 +85,7 @@ fn render_dyn_for_ty() {
 trait Foo<'a> {}
 
 fn foo(foo: &dyn for<'a> Foo<'a>) {}
-    // ^^^ &dyn Foo
+    // ^^^ &dyn Foo<'static>
 "#,
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
index 963b4a2aba0..80d5a0ae001 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
@@ -1109,7 +1109,7 @@ fn var_args() {
 #[lang = "va_list"]
 pub struct VaListImpl<'f>;
 fn my_fn(foo: ...) {}
-       //^^^ VaListImpl<'_>
+       //^^^ VaListImpl<'static>
 "#,
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index 9a8ebd07d01..8565b60210b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -896,13 +896,13 @@ fn flush(&self) {
 "#,
         expect![[r#"
             123..127 'self': &Mutex<T>
-            150..152 '{}': MutexGuard<'_, T>
+            150..152 '{}': MutexGuard<'static, T>
             234..238 'self': &{unknown}
             240..290 '{     ...()); }': ()
             250..251 'w': &Mutex<BufWriter>
             276..287 '*(w.lock())': BufWriter
             278..279 'w': &Mutex<BufWriter>
-            278..286 'w.lock()': MutexGuard<'_, BufWriter>
+            278..286 'w.lock()': MutexGuard<'static, BufWriter>
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index 917e9f44085..f39404593e5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -3092,7 +3092,7 @@ fn main() {
             389..394 'boxed': Box<Foo<i32>>
             389..406 'boxed....nner()': &i32
             416..421 'good1': &i32
-            424..438 'Foo::get_inner': fn get_inner<i32>(&Box<Foo<i32>>) -> &i32
+            424..438 'Foo::get_inner': fn get_inner<i32, 'static>(&Box<Foo<i32>>) -> &i32
             424..446 'Foo::g...boxed)': &i32
             439..445 '&boxed': &Box<Foo<i32>>
             440..445 'boxed': Box<Foo<i32>>
@@ -3100,7 +3100,7 @@ fn main() {
             464..469 'boxed': Box<Foo<i32>>
             464..480 'boxed....self()': &Foo<i32>
             490..495 'good2': &Foo<i32>
-            498..511 'Foo::get_self': fn get_self<i32>(&Box<Foo<i32>>) -> &Foo<i32>
+            498..511 'Foo::get_self': fn get_self<i32, 'static>(&Box<Foo<i32>>) -> &Foo<i32>
             498..519 'Foo::g...boxed)': &Foo<i32>
             512..518 '&boxed': &Box<Foo<i32>>
             513..518 'boxed': Box<Foo<i32>>
@@ -3659,7 +3659,7 @@ fn main() {
     let are = "are";
     let count = 10;
     builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'_>
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'static>
 }
 "#,
     );
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 b80cfe18e4c..759af18c98b 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
@@ -1279,6 +1279,40 @@ fn bar() {
 }
 
 #[test]
+fn argument_assoc_impl_trait() {
+    check_infer(
+        r#"
+trait Outer {
+    type Item;
+}
+
+trait Inner { }
+
+fn foo<T: Outer<Item = impl Inner>>(baz: T) {
+}
+
+impl Outer for usize {
+    type Item = usize;
+}
+
+impl Inner for usize {}
+
+fn main() {
+    foo(2);
+}
+"#,
+        expect![[r#"
+            85..88 'baz': T
+            93..96 '{ }': ()
+            182..197 '{     foo(2); }': ()
+            188..191 'foo': fn foo<usize>(usize)
+            188..194 'foo(2)': ()
+            192..193 '2': usize
+        "#]],
+    );
+}
+
+#[test]
 fn simple_return_pos_impl_trait() {
     cov_mark::check!(lower_rpit);
     check_infer(
@@ -4655,3 +4689,78 @@ fn f<T: Send, U>() {
 "#,
     );
 }
+
+#[test]
+fn associated_type_impl_trait() {
+    check_types(
+        r#"
+trait Foo {}
+struct S1;
+impl Foo for S1 {}
+
+trait Bar {
+    type Item;
+    fn bar(&self) -> Self::Item;
+}
+struct S2;
+impl Bar for S2 {
+    type Item = impl Foo;
+    fn bar(&self) -> Self::Item {
+        S1
+    }
+}
+
+fn test() {
+    let x = S2.bar();
+      //^ impl Foo + ?Sized
+}
+        "#,
+    );
+}
+
+#[test]
+fn associated_type_impl_traits_complex() {
+    check_types(
+        r#"
+struct Unary<T>(T);
+struct Binary<T, U>(T, U);
+
+trait Foo {}
+struct S1;
+impl Foo for S1 {}
+
+trait Bar {
+    type Item;
+    fn bar(&self) -> Unary<Self::Item>;
+}
+struct S2;
+impl Bar for S2 {
+    type Item = Unary<impl Foo>;
+    fn bar(&self) -> Unary<<Self as Bar>::Item> {
+        Unary(Unary(S1))
+    }
+}
+
+trait Baz {
+    type Target1;
+    type Target2;
+    fn baz(&self) -> Binary<Self::Target1, Self::Target2>;
+}
+struct S3;
+impl Baz for S3 {
+    type Target1 = impl Foo;
+    type Target2 = Unary<impl Bar>;
+    fn baz(&self) -> Binary<Self::Target1, Self::Target2> {
+        Binary(S1, Unary(S2))
+    }
+}
+
+fn test() {
+    let x = S3.baz();
+      //^ Binary<impl Foo + ?Sized, Unary<impl Bar + ?Sized>>
+    let y = x.1.0.bar();
+      //^ Unary<Bar::Item<impl Bar + ?Sized>>
+}
+        "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 8bd57820d2c..afd4d1f271d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -9,18 +9,18 @@ use chalk_ir::{
     fold::{FallibleTypeFolder, Shift},
     BoundVar, DebruijnIndex,
 };
-use either::Either;
 use hir_def::{
     db::DefDatabase,
     generics::{
-        GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
-        WherePredicateTypeTarget,
+        GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
+        TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
     },
     lang_item::LangItem,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
-    ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId, Lookup,
-    OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId,
+    ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, ItemContainerId,
+    LifetimeParamId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId,
+    TypeParamId,
 };
 use hir_expand::name::Name;
 use intern::Interned;
@@ -270,64 +270,130 @@ pub(crate) struct Generics {
 }
 
 impl Generics {
-    pub(crate) fn iter_id(&self) -> impl Iterator<Item = Either<TypeParamId, ConstParamId>> + '_ {
-        self.iter().map(|(id, data)| match data {
-            TypeOrConstParamData::TypeParamData(_) => Either::Left(TypeParamId::from_unchecked(id)),
-            TypeOrConstParamData::ConstParamData(_) => {
-                Either::Right(ConstParamId::from_unchecked(id))
-            }
-        })
+    pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
+        self.iter().map(|(id, _)| id)
     }
 
     /// Iterator over types and const params of self, then parent.
     pub(crate) fn iter<'a>(
         &'a self,
-    ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
-        let to_toc_id = |it: &'a Generics| {
-            move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
+    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a {
+        let from_toc_id = |it: &'a Generics| {
+            move |(local_id, p): (_, &'a TypeOrConstParamData)| {
+                let id = TypeOrConstParamId { parent: it.def, local_id };
+                match p {
+                    TypeOrConstParamData::TypeParamData(p) => (
+                        GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
+                        GenericParamDataRef::TypeParamData(p),
+                    ),
+                    TypeOrConstParamData::ConstParamData(p) => (
+                        GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
+                        GenericParamDataRef::ConstParamData(p),
+                    ),
+                }
+            }
         };
-        self.params.iter().map(to_toc_id(self)).chain(self.iter_parent())
+
+        let from_lt_id = |it: &'a Generics| {
+            move |(local_id, p): (_, &'a LifetimeParamData)| {
+                (
+                    GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
+                    GenericParamDataRef::LifetimeParamData(p),
+                )
+            }
+        };
+
+        let lt_iter = self.params.iter_lt().map(from_lt_id(self));
+        self.params.iter().map(from_toc_id(self)).chain(lt_iter).chain(self.iter_parent())
     }
 
     /// Iterate over types and const params without parent params.
     pub(crate) fn iter_self<'a>(
         &'a self,
-    ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
-        let to_toc_id = |it: &'a Generics| {
-            move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
+    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a {
+        let from_toc_id = |it: &'a Generics| {
+            move |(local_id, p): (_, &'a TypeOrConstParamData)| {
+                let id = TypeOrConstParamId { parent: it.def, local_id };
+                match p {
+                    TypeOrConstParamData::TypeParamData(p) => (
+                        GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
+                        GenericParamDataRef::TypeParamData(p),
+                    ),
+                    TypeOrConstParamData::ConstParamData(p) => (
+                        GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
+                        GenericParamDataRef::ConstParamData(p),
+                    ),
+                }
+            }
+        };
+
+        let from_lt_id = |it: &'a Generics| {
+            move |(local_id, p): (_, &'a LifetimeParamData)| {
+                (
+                    GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
+                    GenericParamDataRef::LifetimeParamData(p),
+                )
+            }
         };
-        self.params.iter().map(to_toc_id(self))
+
+        self.params.iter().map(from_toc_id(self)).chain(self.params.iter_lt().map(from_lt_id(self)))
     }
 
     /// Iterator over types and const params of parent.
-    pub(crate) fn iter_parent(
-        &self,
-    ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &TypeOrConstParamData)> {
+    #[allow(clippy::needless_lifetimes)]
+    pub(crate) fn iter_parent<'a>(
+        &'a self,
+    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a {
         self.parent_generics().into_iter().flat_map(|it| {
-            let to_toc_id =
-                move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p);
-            it.params.iter().map(to_toc_id)
+            let from_toc_id = move |(local_id, p): (_, &'a TypeOrConstParamData)| {
+                let id = TypeOrConstParamId { parent: it.def, local_id };
+                match p {
+                    TypeOrConstParamData::TypeParamData(p) => (
+                        GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
+                        GenericParamDataRef::TypeParamData(p),
+                    ),
+                    TypeOrConstParamData::ConstParamData(p) => (
+                        GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
+                        GenericParamDataRef::ConstParamData(p),
+                    ),
+                }
+            };
+
+            let from_lt_id = move |(local_id, p): (_, &'a LifetimeParamData)| {
+                (
+                    GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
+                    GenericParamDataRef::LifetimeParamData(p),
+                )
+            };
+            let lt_iter = it.params.iter_lt().map(from_lt_id);
+            it.params.iter().map(from_toc_id).chain(lt_iter)
         })
     }
 
     /// Returns total number of generic parameters in scope, including those from parent.
     pub(crate) fn len(&self) -> usize {
         let parent = self.parent_generics().map_or(0, Generics::len);
-        let child = self.params.type_or_consts.len();
+        let child = self.params.len();
         parent + child
     }
 
-    /// Returns numbers of generic parameters excluding those from parent.
+    /// Returns numbers of generic parameters and lifetimes excluding those from parent.
     pub(crate) fn len_self(&self) -> usize {
+        self.params.len()
+    }
+
+    /// Returns number of generic parameter excluding those from parent
+    fn len_params(&self) -> usize {
         self.params.type_or_consts.len()
     }
 
-    /// (parent total, self param, type param list, const param list, impl trait)
-    pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
+    /// (parent total, self param, type params, const params, impl trait list, lifetimes)
+    pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize, usize) {
         let mut self_params = 0;
         let mut type_params = 0;
         let mut impl_trait_params = 0;
         let mut const_params = 0;
+        let mut lifetime_params = 0;
         self.params.iter().for_each(|(_, data)| match data {
             TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                 TypeParamProvenance::TypeParamList => type_params += 1,
@@ -337,8 +403,10 @@ impl Generics {
             TypeOrConstParamData::ConstParamData(_) => const_params += 1,
         });
 
+        self.params.iter_lt().for_each(|(_, _)| lifetime_params += 1);
+
         let parent_len = self.parent_generics().map_or(0, Generics::len);
-        (parent_len, self_params, type_params, const_params, impl_trait_params)
+        (parent_len, self_params, type_params, const_params, impl_trait_params, lifetime_params)
     }
 
     pub(crate) fn param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
@@ -358,6 +426,26 @@ impl Generics {
         }
     }
 
+    pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option<usize> {
+        Some(self.find_lifetime(lifetime)?.0)
+    }
+
+    fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<(usize, &LifetimeParamData)> {
+        if lifetime.parent == self.def {
+            let (idx, (_local_id, data)) = self
+                .params
+                .iter_lt()
+                .enumerate()
+                .find(|(_, (idx, _))| *idx == lifetime.local_id)?;
+
+            Some((self.len_params() + idx, data))
+        } else {
+            self.parent_generics()
+                .and_then(|g| g.find_lifetime(lifetime))
+                .map(|(idx, data)| (self.len_self() + idx, data))
+        }
+    }
+
     pub(crate) fn parent_generics(&self) -> Option<&Generics> {
         self.parent_generics.as_deref()
     }
@@ -371,10 +459,15 @@ impl Generics {
         Substitution::from_iter(
             Interner,
             self.iter_id().enumerate().map(|(idx, id)| match id {
-                Either::Left(_) => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
-                Either::Right(id) => BoundVar::new(debruijn, idx)
+                GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx)
                     .to_const(Interner, db.const_param_ty(id))
                     .cast(Interner),
+                GenericParamId::TypeParamId(_) => {
+                    BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner)
+                }
+                GenericParamId::LifetimeParamId(_) => {
+                    BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
+                }
             }),
         )
     }
@@ -384,12 +477,15 @@ impl Generics {
         Substitution::from_iter(
             Interner,
             self.iter_id().map(|id| match id {
-                Either::Left(id) => {
+                GenericParamId::TypeParamId(id) => {
                     crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
                 }
-                Either::Right(id) => crate::to_placeholder_idx(db, id.into())
+                GenericParamId::ConstParamId(id) => crate::to_placeholder_idx(db, id.into())
                     .to_const(Interner, db.const_param_ty(id))
                     .cast(Interner),
+                GenericParamId::LifetimeParamId(id) => {
+                    crate::lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner)
+                }
             }),
         )
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index c5d44c11f2c..23c6b078b96 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -186,18 +186,29 @@ impl HirDisplay for Struct {
             }
             StructKind::Record => {
                 let has_where_clause = write_where_clause(def_id, f)?;
-                let fields = self.fields(f.db);
-                f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
-                if fields.is_empty() {
-                    f.write_str("{}")?;
-                } else {
-                    f.write_str("{\n")?;
-                    for field in self.fields(f.db) {
-                        f.write_str("    ")?;
-                        field.hir_fmt(f)?;
-                        f.write_str(",\n")?;
+                if let Some(limit) = f.entity_limit {
+                    let fields = self.fields(f.db);
+                    let count = fields.len().min(limit);
+                    f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
+                    if count == 0 {
+                        if fields.is_empty() {
+                            f.write_str("{}")?;
+                        } else {
+                            f.write_str("{ /* … */ }")?;
+                        }
+                    } else {
+                        f.write_str(" {\n")?;
+                        for field in &fields[..count] {
+                            f.write_str("    ")?;
+                            field.hir_fmt(f)?;
+                            f.write_str(",\n")?;
+                        }
+
+                        if fields.len() > count {
+                            f.write_str("    /* … */\n")?;
+                        }
+                        f.write_str("}")?;
                     }
-                    f.write_str("}")?;
                 }
             }
             StructKind::Unit => _ = write_where_clause(def_id, f)?,
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index b922aa8e46d..106056c2fc3 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -38,7 +38,7 @@ mod display;
 use std::{iter, mem::discriminant, ops::ControlFlow};
 
 use arrayvec::ArrayVec;
-use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId};
+use base_db::{CrateDisplayName, CrateId, CrateOrigin, FileId};
 use either::Either;
 use hir_def::{
     body::{BodyDiagnostic, SyntheticSyntax},
@@ -65,7 +65,7 @@ use hir_ty::{
     consteval::{try_const_usize, unknown_const_as_generic, ConstExt},
     db::InternedClosure,
     diagnostics::BodyValidationDiagnostic,
-    known_const_to_ast,
+    error_lifetime, known_const_to_ast,
     layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
     method_resolution::{self, TyFingerprint},
     mir::{interpret_mir, MutBorrowKind},
@@ -79,6 +79,7 @@ use hir_ty::{
 use itertools::Itertools;
 use nameres::diagnostics::DefDiagnosticKind;
 use rustc_hash::FxHashSet;
+use span::Edition;
 use stdx::{impl_from, never};
 use syntax::{
     ast::{self, HasAttrs as _, HasName},
@@ -971,7 +972,7 @@ fn precise_macro_call_location(
                 MacroKind::ProcMacro,
             )
         }
-        MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
+        MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => {
             let node = ast_id.to_node(db.upcast());
             // Compute the precise location of the macro name's token in the derive
             // list.
@@ -1099,13 +1100,14 @@ impl Field {
             VariantDef::Union(it) => it.id.into(),
             VariantDef::Variant(it) => it.parent_enum(db).id.into(),
         };
-        let mut generics = generics.map(|it| it.ty.clone());
+        let mut generics = generics.map(|it| it.ty);
         let substs = TyBuilder::subst_for_def(db, def_id, None)
             .fill(|x| match x {
                 ParamKind::Type => {
                     generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
                 }
                 ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+                ParamKind::Lifetime => error_lifetime().cast(Interner),
             })
             .build();
         let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
@@ -1416,7 +1418,7 @@ impl Adt {
     }
 
     pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
-        if db.generic_params(self.into()).iter().count() != 0 {
+        if !db.generic_params(self.into()).is_empty() {
             return Err(LayoutError::HasPlaceholder);
         }
         let krate = self.krate(db).id;
@@ -1440,13 +1442,14 @@ impl Adt {
     /// the greatest API, FIXME find a better one.
     pub fn ty_with_args(self, db: &dyn HirDatabase, args: impl Iterator<Item = Type>) -> Type {
         let id = AdtId::from(self);
-        let mut it = args.map(|t| t.ty.clone());
+        let mut it = args.map(|t| t.ty);
         let ty = TyBuilder::def_ty(db, id.into(), None)
             .fill(|x| {
                 let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
                 match x {
                     ParamKind::Type => r.cast(Interner),
                     ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+                    ParamKind::Lifetime => error_lifetime().cast(Interner),
                 }
             })
             .build();
@@ -1859,12 +1862,13 @@ impl Function {
             ItemContainerId::TraitId(it) => Some(it.into()),
             ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
         };
-        let mut generics = generics.map(|it| it.ty.clone());
+        let mut generics = generics.map(|it| it.ty);
         let mut filler = |x: &_| match x {
             ParamKind::Type => {
                 generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
             }
             ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+            ParamKind::Lifetime => error_lifetime().cast(Interner),
         };
 
         let parent_substs =
@@ -1954,7 +1958,7 @@ impl Function {
             ItemContainerId::TraitId(it) => Some(it.into()),
             ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
         };
-        let mut generics = generics.map(|it| it.ty.clone());
+        let mut generics = generics.map(|it| it.ty);
         let parent_substs = parent_id.map(|id| {
             TyBuilder::subst_for_def(db, id, None)
                 .fill(|x| match x {
@@ -1963,6 +1967,7 @@ impl Function {
                         .unwrap_or_else(|| TyKind::Error.intern(Interner))
                         .cast(Interner),
                     ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+                    ParamKind::Lifetime => error_lifetime().cast(Interner),
                 })
                 .build()
         });
@@ -2007,8 +2012,7 @@ impl Function {
         }
         let data = db.function_data(self.id);
 
-        data.name.to_smol_str() == "main"
-            || data.attrs.export_name().map(core::ops::Deref::deref) == Some("main")
+        data.name.to_smol_str() == "main" || data.attrs.export_name() == Some("main")
     }
 
     /// Does this function have the ignore attribute?
@@ -2215,12 +2219,13 @@ impl SelfParam {
             }
         };
 
-        let mut generics = generics.map(|it| it.ty.clone());
+        let mut generics = generics.map(|it| it.ty);
         let mut filler = |x: &_| match x {
             ParamKind::Type => {
                 generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
             }
             ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+            ParamKind::Lifetime => error_lifetime().cast(Interner),
         };
 
         let parent_substs = TyBuilder::subst_for_def(db, parent_id, None).fill(&mut filler).build();
@@ -2592,7 +2597,7 @@ impl Macro {
             },
             MacroId::ProcMacroId(it) => match it.lookup(db.upcast()).kind {
                 ProcMacroKind::CustomDerive => MacroKind::Derive,
-                ProcMacroKind::FuncLike => MacroKind::ProcMacro,
+                ProcMacroKind::Bang => MacroKind::ProcMacro,
                 ProcMacroKind::Attr => MacroKind::Attr,
             },
         }
@@ -3628,16 +3633,41 @@ impl Impl {
                     .filter(filter),
             );
         }
+
+        if let Some(block) =
+            ty.adt_id(Interner).and_then(|def| def.0.module(db.upcast()).containing_block())
+        {
+            if let Some(inherent_impls) = db.inherent_impls_in_block(block) {
+                all.extend(
+                    inherent_impls.for_self_ty(&ty).iter().cloned().map(Self::from).filter(filter),
+                );
+            }
+            if let Some(trait_impls) = db.trait_impls_in_block(block) {
+                all.extend(
+                    trait_impls
+                        .for_self_ty_without_blanket_impls(fp)
+                        .map(Self::from)
+                        .filter(filter),
+                );
+            }
+        }
+
         all
     }
 
     pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> {
-        let krate = trait_.module(db).krate();
+        let module = trait_.module(db);
+        let krate = module.krate();
         let mut all = Vec::new();
         for Crate { id } in krate.transitive_reverse_dependencies(db) {
             let impls = db.trait_impls_in_crate(id);
             all.extend(impls.for_trait(trait_.id).map(Self::from))
         }
+        if let Some(block) = module.id.containing_block() {
+            if let Some(trait_impls) = db.trait_impls_in_block(block) {
+                all.extend(trait_impls.for_trait(trait_.id).map(Self::from));
+            }
+        }
         all
     }
 
@@ -3683,7 +3713,7 @@ impl Impl {
         let macro_file = src.file_id.macro_file()?;
         let loc = macro_file.macro_call_id.lookup(db.upcast());
         let (derive_attr, derive_index) = match loc.kind {
-            MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
+            MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => {
                 let module_id = self.id.lookup(db.upcast()).container;
                 (
                     db.crate_def_map(module_id.krate())[module_id.local_id]
@@ -4114,6 +4144,7 @@ impl Type {
                         // FIXME: this code is not covered in tests.
                         unknown_const_as_generic(ty.clone())
                     }
+                    ParamKind::Lifetime => error_lifetime().cast(Interner),
                 }
             })
             .build();
@@ -4144,6 +4175,7 @@ impl Type {
                 match it {
                     ParamKind::Type => args.next().unwrap().ty.clone().cast(Interner),
                     ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+                    ParamKind::Lifetime => error_lifetime().cast(Interner),
                 }
             })
             .build();
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
index 102e0ca4c3d..63b2a2506f8 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
@@ -177,7 +177,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
                 // Note that we need special case for 0 param constructors because of multi cartesian
                 // product
                 let variant_exprs: Vec<Expr> = if param_exprs.is_empty() {
-                    vec![Expr::Variant { variant, generics: generics.clone(), params: Vec::new() }]
+                    vec![Expr::Variant { variant, generics, params: Vec::new() }]
                 } else {
                     param_exprs
                         .into_iter()
@@ -462,7 +462,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
 
 /// # Impl method tactic
 ///
-/// Attempts to to call methods on types from lookup table.
+/// Attempts to call methods on types from lookup table.
 /// This includes both functions from direct impl blocks as well as functions from traits.
 /// Methods defined in impl blocks that are generic and methods that are themselves have
 /// generics are ignored for performance reasons.
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index d111005c2ec..65ce3e822c5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -5617,7 +5617,7 @@ fn func<T: Debug>(i: Struct<'_, T>) {
     fun_name(i);
 }
 
-fn $0fun_name(i: Struct<'_, T>) {
+fn $0fun_name(i: Struct<'static, T>) {
     foo(i);
 }
 "#,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index 38f40b8d58b..2150003bc14 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -614,7 +614,7 @@ struct Foo<'a, T> {
 }
 
 impl<'a, T> Foo<'a, T> {
-    $0fn bar(self, mut b: Vec<&'a Bar<'_, T>>) -> &'a Bar<'_, T> {
+    $0fn bar(self, mut b: Vec<&'a Bar<'a, T>>) -> &'a Bar<'a, T> {
         self.field.bar(b)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
index 24a1f9492e2..a4f092cc498 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
@@ -961,11 +961,11 @@ struct Foo { field: i32 }
 impl Foo { fn foo(&self) { $0 } }"#,
             expect![[r#"
                 fd self.field i32
+                me self.foo() fn(&self)
                 lc self       &Foo
                 sp Self       Foo
                 st Foo        Foo
                 bt u32        u32
-                me self.foo() fn(&self)
             "#]],
         );
         check(
@@ -975,11 +975,11 @@ struct Foo(i32);
 impl Foo { fn foo(&mut self) { $0 } }"#,
             expect![[r#"
                 fd self.0     i32
+                me self.foo() fn(&mut self)
                 lc self       &mut Foo
                 sp Self       Foo
                 st Foo        Foo
                 bt u32        u32
-                me self.foo() fn(&mut self)
             "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 79467841502..c48672e80ac 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -186,11 +186,11 @@ fn add_function_impl(
         if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." }
     );
 
-    let completion_kind = if func.has_self_param(ctx.db) {
-        CompletionItemKind::Method
+    let completion_kind = CompletionItemKind::SymbolKind(if func.has_self_param(ctx.db) {
+        SymbolKind::Method
     } else {
-        CompletionItemKind::SymbolKind(SymbolKind::Function)
-    };
+        SymbolKind::Function
+    });
 
     let mut item = CompletionItem::new(completion_kind, replacement_range, label);
     item.lookup_by(format!("fn {}", fn_name.display(ctx.db)))
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
index ed32a5db23e..1322c05e30e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
@@ -75,8 +75,8 @@ impl Future for A {}
 fn foo(a: A) { a.$0 }
 "#,
             expect![[r#"
-                kw await                  expr.await
                 me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
+                kw await                  expr.await
                 sn box                    Box::new(expr)
                 sn call                   function(expr)
                 sn dbg                    dbg!(expr)
@@ -102,8 +102,8 @@ fn foo() {
 }
 "#,
             expect![[r#"
-                kw await                  expr.await
                 me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
+                kw await                  expr.await
                 sn box                    Box::new(expr)
                 sn call                   function(expr)
                 sn dbg                    dbg!(expr)
@@ -131,8 +131,8 @@ impl IntoFuture for A {}
 fn foo(a: A) { a.$0 }
 "#,
             expect![[r#"
-                kw await                  expr.await
                 me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
+                kw await                  expr.await
                 sn box                    Box::new(expr)
                 sn call                   function(expr)
                 sn dbg                    dbg!(expr)
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index aa22155feff..995e3f48253 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -540,7 +540,7 @@ impl CompletionContext<'_> {
     /// Whether the given trait is an operator trait or not.
     pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
         match trait_.attrs(self.db).lang() {
-            Some(lang) => OP_TRAIT_LANG_NAMES.contains(&lang.as_str()),
+            Some(lang) => OP_TRAIT_LANG_NAMES.contains(&lang),
             None => false,
         }
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index 357060817c7..b9a2c383bdd 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -342,7 +342,6 @@ pub enum CompletionItemKind {
     BuiltinType,
     InferredType,
     Keyword,
-    Method,
     Snippet,
     UnresolvedReference,
     Expression,
@@ -369,6 +368,7 @@ impl CompletionItemKind {
                 SymbolKind::LifetimeParam => "lt",
                 SymbolKind::Local => "lc",
                 SymbolKind::Macro => "ma",
+                SymbolKind::Method => "me",
                 SymbolKind::ProcMacro => "pm",
                 SymbolKind::Module => "md",
                 SymbolKind::SelfParam => "sp",
@@ -388,7 +388,6 @@ impl CompletionItemKind {
             CompletionItemKind::BuiltinType => "bt",
             CompletionItemKind::InferredType => "it",
             CompletionItemKind::Keyword => "kw",
-            CompletionItemKind::Method => "me",
             CompletionItemKind::Snippet => "sn",
             CompletionItemKind::UnresolvedReference => "??",
             CompletionItemKind::Expression => "ex",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 6d1a5a0bc52..ca0424809ed 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -312,7 +312,7 @@ pub(crate) fn render_expr(
         None => ctx.source_range(),
     };
 
-    let mut item = CompletionItem::new(CompletionItemKind::Expression, source_range, label.clone());
+    let mut item = CompletionItem::new(CompletionItemKind::Expression, source_range, label);
 
     let snippet = format!(
         "{}$0",
@@ -677,10 +677,11 @@ mod tests {
 
     #[track_caller]
     fn check_function_relevance(ra_fixture: &str, expect: Expect) {
-        let actual: Vec<_> = do_completion(ra_fixture, CompletionItemKind::Method)
-            .into_iter()
-            .map(|item| (item.detail.unwrap_or_default(), item.relevance.function))
-            .collect();
+        let actual: Vec<_> =
+            do_completion(ra_fixture, CompletionItemKind::SymbolKind(SymbolKind::Method))
+                .into_iter()
+                .map(|item| (item.detail.unwrap_or_default(), item.relevance.function))
+                .collect();
 
         expect.assert_debug_eq(&actual);
     }
@@ -1392,7 +1393,10 @@ impl S {
     /// Method docs
     fn bar(self) { self.$0 }
 }"#,
-            &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
+            &[
+                CompletionItemKind::SymbolKind(SymbolKind::Method),
+                CompletionItemKind::SymbolKind(SymbolKind::Field),
+            ],
             expect![[r#"
                 [
                     CompletionItem {
@@ -1400,7 +1404,9 @@ impl S {
                         source_range: 94..94,
                         delete: 94..94,
                         insert: "bar()$0",
-                        kind: Method,
+                        kind: SymbolKind(
+                            Method,
+                        ),
                         lookup: "bar",
                         detail: "fn(self)",
                         documentation: Documentation(
@@ -1520,7 +1526,7 @@ impl S {
 }
 fn foo(s: S) { s.$0 }
 "#,
-            CompletionItemKind::Method,
+            CompletionItemKind::SymbolKind(SymbolKind::Method),
             expect![[r#"
                 [
                     CompletionItem {
@@ -1528,7 +1534,9 @@ fn foo(s: S) { s.$0 }
                         source_range: 81..81,
                         delete: 81..81,
                         insert: "the_method()$0",
-                        kind: Method,
+                        kind: SymbolKind(
+                            Method,
+                        ),
                         lookup: "the_method",
                         detail: "fn(&self)",
                         relevance: CompletionRelevance {
@@ -2408,7 +2416,10 @@ impl Foo { fn baz(&self) -> u32 { 0 } }
 
 fn foo(f: Foo) { let _: &u32 = f.b$0 }
 "#,
-            &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
+            &[
+                CompletionItemKind::SymbolKind(SymbolKind::Method),
+                CompletionItemKind::SymbolKind(SymbolKind::Field),
+            ],
             expect![[r#"
                 [
                     CompletionItem {
@@ -2416,7 +2427,9 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
                         source_range: 109..110,
                         delete: 109..110,
                         insert: "baz()$0",
-                        kind: Method,
+                        kind: SymbolKind(
+                            Method,
+                        ),
                         lookup: "baz",
                         detail: "fn(&self) -> u32",
                         relevance: CompletionRelevance {
@@ -2631,7 +2644,7 @@ fn main() {
     let _: bool = (9 > 2).not$0;
 }
     "#,
-            &[CompletionItemKind::Snippet, CompletionItemKind::Method],
+            &[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)],
             expect![[r#"
                 sn not [snippet]
                 me not() (use ops::Not) [type_could_unify+requires_import]
@@ -2664,7 +2677,7 @@ fn main() {
     S.$0
 }
     "#,
-            &[CompletionItemKind::Snippet, CompletionItemKind::Method],
+            &[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)],
             expect![[r#"
                 me f() []
                 sn ref []
@@ -2907,7 +2920,7 @@ fn main() {
 }
 "#,
             &[
-                CompletionItemKind::Method,
+                CompletionItemKind::SymbolKind(SymbolKind::Method),
                 CompletionItemKind::SymbolKind(SymbolKind::Field),
                 CompletionItemKind::SymbolKind(SymbolKind::Function),
             ],
@@ -2918,7 +2931,9 @@ fn main() {
                         source_range: 193..193,
                         delete: 193..193,
                         insert: "flush()$0",
-                        kind: Method,
+                        kind: SymbolKind(
+                            Method,
+                        ),
                         lookup: "flush",
                         detail: "fn(&self)",
                         relevance: CompletionRelevance {
@@ -2941,7 +2956,9 @@ fn main() {
                         source_range: 193..193,
                         delete: 193..193,
                         insert: "write()$0",
-                        kind: Method,
+                        kind: SymbolKind(
+                            Method,
+                        ),
                         lookup: "write",
                         detail: "fn(&self)",
                         relevance: CompletionRelevance {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
index cf9fe1ab307..1634b0a9206 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
@@ -68,11 +68,11 @@ fn render(
     };
     let has_self_param = func.self_param(db).is_some();
     let mut item = CompletionItem::new(
-        if has_self_param {
-            CompletionItemKind::Method
+        CompletionItemKind::SymbolKind(if has_self_param {
+            SymbolKind::Method
         } else {
-            CompletionItemKind::SymbolKind(SymbolKind::Function)
-        },
+            SymbolKind::Function
+        }),
         ctx.source_range(),
         call.clone(),
     );
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index 7749fac40b9..a653314233d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -127,6 +127,7 @@ impl Unit {
             en Enum         Enum
             fn function()   fn()
             fn local_func() fn()
+            me self.foo()   fn(self)
             lc self         Unit
             ma makro!(…)    macro_rules! makro
             md module
@@ -166,7 +167,6 @@ impl Unit {
             kw use
             kw while
             kw while let
-            me self.foo()   fn(self)
             sn macro_rules
             sn pd
             sn ppd
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
index 46a3e97d3e9..3718dff56e8 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
@@ -19,7 +19,7 @@ struct Foo<'lt, T, const C: usize> where $0 {}
             en Enum      Enum
             ma makro!(…) macro_rules! makro
             md module
-            st Foo<…>    Foo<'_, {unknown}, _>
+            st Foo<…>    Foo<'static, {unknown}, _>
             st Record    Record
             st Tuple     Tuple
             st Unit      Unit
@@ -92,7 +92,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
             en Enum      Enum
             ma makro!(…) macro_rules! makro
             md module
-            st Foo<…>    Foo<'_, {unknown}, _>
+            st Foo<…>    Foo<'static, {unknown}, _>
             st Record    Record
             st Tuple     Tuple
             st Unit      Unit
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
index ff32eccfbff..69d8fe91040 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
@@ -1,6 +1,7 @@
 //! Tests that don't fit into a specific category.
 
 use expect_test::{expect, Expect};
+use ide_db::SymbolKind;
 
 use crate::{
     tests::{
@@ -316,15 +317,15 @@ trait Sub: Super {
 fn foo<T: Sub>() { T::$0 }
 "#,
         expect![[r#"
-                ct C2 (as Sub)           const C2: ()
-                ct CONST (as Super)      const CONST: u8
-                fn func() (as Super)     fn()
-                fn subfunc() (as Sub)    fn()
-                ta SubTy (as Sub)        type SubTy
-                ta Ty (as Super)         type Ty
-                me method(…) (as Super)  fn(&self)
-                me submethod(…) (as Sub) fn(&self)
-            "#]],
+            ct C2 (as Sub)           const C2: ()
+            ct CONST (as Super)      const CONST: u8
+            fn func() (as Super)     fn()
+            fn subfunc() (as Sub)    fn()
+            me method(…) (as Super)  fn(&self)
+            me submethod(…) (as Sub) fn(&self)
+            ta SubTy (as Sub)        type SubTy
+            ta Ty (as Super)         type Ty
+        "#]],
     );
 }
 
@@ -356,15 +357,15 @@ impl<T> Sub for Wrap<T> {
 }
 "#,
         expect![[r#"
-                ct C2 (as Sub)           const C2: ()
-                ct CONST (as Super)      const CONST: u8
-                fn func() (as Super)     fn()
-                fn subfunc() (as Sub)    fn()
-                ta SubTy (as Sub)        type SubTy
-                ta Ty (as Super)         type Ty
-                me method(…) (as Super)  fn(&self)
-                me submethod(…) (as Sub) fn(&self)
-            "#]],
+            ct C2 (as Sub)           const C2: ()
+            ct CONST (as Super)      const CONST: u8
+            fn func() (as Super)     fn()
+            fn subfunc() (as Sub)    fn()
+            me method(…) (as Super)  fn(&self)
+            me submethod(…) (as Sub) fn(&self)
+            ta SubTy (as Sub)        type SubTy
+            ta Ty (as Super)         type Ty
+        "#]],
     );
 }
 
@@ -555,10 +556,10 @@ impl Foo {
 }
 "#,
         expect![[r#"
-                ev Bar    Bar
-                ev Baz    Baz
-                me foo(…) fn(self)
-            "#]],
+            me foo(…) fn(self)
+            ev Bar    Bar
+            ev Baz    Baz
+        "#]],
     );
 }
 
@@ -1399,7 +1400,7 @@ fn main() {
     bar.b$0
 }
 "#,
-        CompletionItemKind::Method,
+        CompletionItemKind::SymbolKind(SymbolKind::Method),
         expect!("const fn(&'foo mut self, &Foo) -> !"),
         expect!("pub const fn baz<'foo>(&'foo mut self, x: &'foo Foo) -> !"),
     );
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
index db4ac9381ce..97709728656 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
@@ -20,8 +20,8 @@ struct Foo<'lt, T, const C: usize> {
             en Enum      Enum
             ma makro!(…) macro_rules! makro
             md module
-            sp Self      Foo<'_, {unknown}, _>
-            st Foo<…>    Foo<'_, {unknown}, _>
+            sp Self      Foo<'static, {unknown}, _>
+            st Foo<…>    Foo<'static, {unknown}, _>
             st Record    Record
             st Tuple     Tuple
             st Unit      Unit
@@ -45,8 +45,8 @@ struct Foo<'lt, T, const C: usize>(f$0);
             en Enum       Enum
             ma makro!(…)  macro_rules! makro
             md module
-            sp Self       Foo<'_, {unknown}, _>
-            st Foo<…>     Foo<'_, {unknown}, _>
+            sp Self       Foo<'static, {unknown}, _>
+            st Foo<…>     Foo<'static, {unknown}, _>
             st Record     Record
             st Tuple      Tuple
             st Unit       Unit
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index 0d5a93f7b8e..357209ceb0b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -346,6 +346,7 @@ pub enum SymbolKind {
     Enum,
     Field,
     Function,
+    Method,
     Impl,
     Label,
     LifetimeParam,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
index 8ccea99e9e1..edd05009332 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
@@ -26,6 +26,7 @@ text-edit.workspace = true
 cfg.workspace = true
 hir.workspace = true
 ide-db.workspace = true
+paths.workspace = true
 
 [dev-dependencies]
 expect-test = "1.4.0"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index 67daa172b27..045154614f8 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -23,6 +23,7 @@ mod tests {
         },
         DiagnosticsConfig,
     };
+    use test_utils::skip_slow_tests;
 
     #[track_caller]
     fn check_diagnostics_no_bails(ra_fixture: &str) {
@@ -1004,6 +1005,32 @@ fn f() {
         );
     }
 
+    #[test]
+    fn exponential_match() {
+        if skip_slow_tests() {
+            return;
+        }
+        // Constructs a match where match checking takes exponential time. Ensures we bail early.
+        use std::fmt::Write;
+        let struct_arity = 50;
+        let mut code = String::new();
+        write!(code, "struct BigStruct {{").unwrap();
+        for i in 0..struct_arity {
+            write!(code, "  field{i}: bool,").unwrap();
+        }
+        write!(code, "}}").unwrap();
+        write!(code, "fn big_match(s: BigStruct) {{").unwrap();
+        write!(code, "  match s {{").unwrap();
+        for i in 0..struct_arity {
+            write!(code, "    BigStruct {{ field{i}: true, ..}} => {{}},").unwrap();
+            write!(code, "    BigStruct {{ field{i}: false, ..}} => {{}},").unwrap();
+        }
+        write!(code, "    _ => {{}},").unwrap();
+        write!(code, "  }}").unwrap();
+        write!(code, "}}").unwrap();
+        check_diagnostics_no_bails(&code);
+    }
+
     mod rust_unstable {
         use super::*;
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 34a0038295f..00352266ddb 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -7,7 +7,11 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 // Diagnostic: need-mut
 //
 // This diagnostic is triggered on mutating an immutable variable.
-pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Diagnostic {
+pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option<Diagnostic> {
+    if d.span.file_id.macro_file().is_some() {
+        // FIXME: Our infra can't handle allow from within macro expansions rn
+        return None;
+    }
     let fixes = (|| {
         if d.local.is_ref(ctx.sema.db) {
             // There is no simple way to add `mut` to `ref x` and `ref mut x`
@@ -29,24 +33,30 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Diagno
             use_range,
         )])
     })();
-    Diagnostic::new_with_syntax_node_ptr(
-        ctx,
-        // FIXME: `E0384` is not the only error that this diagnostic handles
-        DiagnosticCode::RustcHardError("E0384"),
-        format!(
-            "cannot mutate immutable variable `{}`",
-            d.local.name(ctx.sema.db).display(ctx.sema.db)
-        ),
-        d.span,
+    Some(
+        Diagnostic::new_with_syntax_node_ptr(
+            ctx,
+            // FIXME: `E0384` is not the only error that this diagnostic handles
+            DiagnosticCode::RustcHardError("E0384"),
+            format!(
+                "cannot mutate immutable variable `{}`",
+                d.local.name(ctx.sema.db).display(ctx.sema.db)
+            ),
+            d.span,
+        )
+        .with_fixes(fixes),
     )
-    .with_fixes(fixes)
 }
 
 // Diagnostic: unused-mut
 //
 // This diagnostic is triggered when a mutable variable isn't actually mutated.
-pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Diagnostic {
+pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Option<Diagnostic> {
     let ast = d.local.primary_source(ctx.sema.db).syntax_ptr();
+    if ast.file_id.macro_file().is_some() {
+        // FIXME: Our infra can't handle allow from within macro expansions rn
+        return None;
+    }
     let fixes = (|| {
         let file_id = ast.file_id.file_id()?;
         let mut edit_builder = TextEdit::builder();
@@ -70,14 +80,16 @@ pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Di
         )])
     })();
     let ast = d.local.primary_source(ctx.sema.db).syntax_ptr();
-    Diagnostic::new_with_syntax_node_ptr(
-        ctx,
-        DiagnosticCode::RustcLint("unused_mut"),
-        "variable does not need to be mutable",
-        ast,
+    Some(
+        Diagnostic::new_with_syntax_node_ptr(
+            ctx,
+            DiagnosticCode::RustcLint("unused_mut"),
+            "variable does not need to be mutable",
+            ast,
+        )
+        .experimental() // Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive.
+        .with_fixes(fixes),
     )
-    .experimental() // Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive.
-    .with_fixes(fixes)
 }
 
 pub(super) fn token(parent: &SyntaxNode, kind: SyntaxKind) -> Option<SyntaxToken> {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
index 7a040e46e33..d831878044d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
@@ -12,7 +12,12 @@ use crate::{adjusted_display_range, fix, Diagnostic, DiagnosticCode, Diagnostics
 pub(crate) fn remove_trailing_return(
     ctx: &DiagnosticsContext<'_>,
     d: &RemoveTrailingReturn,
-) -> Diagnostic {
+) -> Option<Diagnostic> {
+    if d.return_expr.file_id.macro_file().is_some() {
+        // FIXME: Our infra can't handle allow from within macro expansions rn
+        return None;
+    }
+
     let display_range = adjusted_display_range(ctx, d.return_expr, &|return_expr| {
         return_expr
             .syntax()
@@ -20,12 +25,14 @@ pub(crate) fn remove_trailing_return(
             .and_then(ast::ExprStmt::cast)
             .map(|stmt| stmt.syntax().text_range())
     });
-    Diagnostic::new(
-        DiagnosticCode::Clippy("needless_return"),
-        "replace return <expr>; with <expr>",
-        display_range,
+    Some(
+        Diagnostic::new(
+            DiagnosticCode::Clippy("needless_return"),
+            "replace return <expr>; with <expr>",
+            display_range,
+        )
+        .with_fixes(fixes(ctx, d)),
     )
-    .with_fixes(fixes(ctx, d))
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveTrailingReturn) -> Option<Vec<Assist>> {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
index f68e6982385..448df1ca163 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
@@ -21,23 +21,30 @@ use crate::{
 pub(crate) fn remove_unnecessary_else(
     ctx: &DiagnosticsContext<'_>,
     d: &RemoveUnnecessaryElse,
-) -> Diagnostic {
+) -> Option<Diagnostic> {
+    if d.if_expr.file_id.macro_file().is_some() {
+        // FIXME: Our infra can't handle allow from within macro expansions rn
+        return None;
+    }
+
     let display_range = adjusted_display_range(ctx, d.if_expr, &|if_expr| {
         if_expr.else_token().as_ref().map(SyntaxToken::text_range)
     });
-    Diagnostic::new(
-        DiagnosticCode::Ra("remove-unnecessary-else", Severity::WeakWarning),
-        "remove unnecessary else block",
-        display_range,
+    Some(
+        Diagnostic::new(
+            DiagnosticCode::Ra("remove-unnecessary-else", Severity::WeakWarning),
+            "remove unnecessary else block",
+            display_range,
+        )
+        .experimental()
+        .with_fixes(fixes(ctx, d)),
     )
-    .experimental()
-    .with_fixes(fixes(ctx, d))
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveUnnecessaryElse) -> Option<Vec<Assist>> {
     let root = ctx.sema.db.parse_or_expand(d.if_expr.file_id);
     let if_expr = d.if_expr.value.to_node(&root);
-    let if_expr = ctx.sema.original_ast_node(if_expr.clone())?;
+    let if_expr = ctx.sema.original_ast_node(if_expr)?;
 
     let mut indent = IndentLevel::from_node(if_expr.syntax());
     let has_parent_if_expr = if_expr.syntax().parent().and_then(ast::IfExpr::cast).is_some();
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index becc24ab21e..b9327f85567 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -8,6 +8,7 @@ use ide_db::{
     source_change::SourceChange,
     RootDatabase,
 };
+use paths::Utf8Component;
 use syntax::{
     ast::{self, edit::IndentLevel, HasModuleItem, HasName},
     AstNode, TextRange,
@@ -84,10 +85,10 @@ fn fixes(ctx: &DiagnosticsContext<'_>, file_id: FileId) -> Option<Vec<Assist>> {
 
         // try resolving the relative difference of the paths as inline modules
         let mut current = root_module;
-        for ele in rel.as_ref().components() {
+        for ele in rel.as_utf8_path().components() {
             let seg = match ele {
-                std::path::Component::Normal(seg) => seg.to_str()?,
-                std::path::Component::RootDir => continue,
+                Utf8Component::Normal(seg) => seg,
+                Utf8Component::RootDir => continue,
                 // shouldn't occur
                 _ => continue 'crates,
             };
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 a9e1d07d7c5..cd251faab9a 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
@@ -14,18 +14,24 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 pub(crate) fn unused_variables(
     ctx: &DiagnosticsContext<'_>,
     d: &hir::UnusedVariable,
-) -> Diagnostic {
+) -> Option<Diagnostic> {
     let ast = d.local.primary_source(ctx.sema.db).syntax_ptr();
+    if ast.file_id.macro_file().is_some() {
+        // FIXME: Our infra can't handle allow from within macro expansions rn
+        return None;
+    }
     let diagnostic_range = ctx.sema.diagnostics_display_range(ast);
     let var_name = d.local.primary_source(ctx.sema.db).syntax().to_string();
-    Diagnostic::new_with_syntax_node_ptr(
-        ctx,
-        DiagnosticCode::RustcLint("unused_variables"),
-        "unused variable",
-        ast,
+    Some(
+        Diagnostic::new_with_syntax_node_ptr(
+            ctx,
+            DiagnosticCode::RustcLint("unused_variables"),
+            "unused variable",
+            ast,
+        )
+        .with_fixes(fixes(&var_name, diagnostic_range, ast.file_id.is_macro()))
+        .experimental(),
     )
-    .with_fixes(fixes(&var_name, diagnostic_range, ast.file_id.is_macro()))
-    .experimental()
 }
 
 fn fixes(var_name: &String, diagnostic_range: FileRange, is_in_marco: bool) -> Option<Vec<Assist>> {
@@ -47,7 +53,7 @@ fn fixes(var_name: &String, diagnostic_range: FileRange, is_in_marco: bool) -> O
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::{check_diagnostics, check_fix, check_no_fix};
+    use crate::tests::{check_diagnostics, check_fix};
 
     #[test]
     fn unused_variables_simple() {
@@ -193,7 +199,7 @@ fn main() {
 
     #[test]
     fn no_fix_for_marco() {
-        check_no_fix(
+        check_diagnostics(
             r#"
 macro_rules! my_macro {
     () => {
@@ -202,7 +208,7 @@ macro_rules! my_macro {
 }
 
 fn main() {
-    $0my_macro!();
+    my_macro!();
 }
 "#,
         );
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 0df6f0e0373..270cf844c65 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -330,7 +330,6 @@ pub fn diagnostics(
     }
 
     for diag in diags {
-        #[rustfmt::skip]
         let d = match diag {
             AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d),
             AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) {
@@ -361,7 +360,10 @@ pub fn diagnostics(
             AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
             AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
             AnyDiagnostic::MovedOutOfRef(d) => handlers::moved_out_of_ref::moved_out_of_ref(&ctx, &d),
-            AnyDiagnostic::NeedMut(d) => handlers::mutability_errors::need_mut(&ctx, &d),
+            AnyDiagnostic::NeedMut(d) => match handlers::mutability_errors::need_mut(&ctx, &d) {
+                Some(it) => it,
+                None => continue,
+            },
             AnyDiagnostic::NonExhaustiveLet(d) => handlers::non_exhaustive_let::non_exhaustive_let(&ctx, &d),
             AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d),
             AnyDiagnostic::PrivateAssocItem(d) => handlers::private_assoc_item::private_assoc_item(&ctx, &d),
@@ -385,12 +387,24 @@ pub fn diagnostics(
             AnyDiagnostic::UnresolvedMethodCall(d) => handlers::unresolved_method::unresolved_method(&ctx, &d),
             AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
             AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled),
-            AnyDiagnostic::UnusedMut(d) => handlers::mutability_errors::unused_mut(&ctx, &d),
-            AnyDiagnostic::UnusedVariable(d) => handlers::unused_variables::unused_variables(&ctx, &d),
+            AnyDiagnostic::UnusedMut(d) => match handlers::mutability_errors::unused_mut(&ctx, &d) {
+                Some(it) => it,
+                None => continue,
+            },
+            AnyDiagnostic::UnusedVariable(d) => match handlers::unused_variables::unused_variables(&ctx, &d) {
+                Some(it) => it,
+                None => continue,
+            },
             AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
             AnyDiagnostic::MismatchedTupleStructPatArgCount(d) => handlers::mismatched_arg_count::mismatched_tuple_struct_pat_arg_count(&ctx, &d),
-            AnyDiagnostic::RemoveTrailingReturn(d) => handlers::remove_trailing_return::remove_trailing_return(&ctx, &d),
-            AnyDiagnostic::RemoveUnnecessaryElse(d) => handlers::remove_unnecessary_else::remove_unnecessary_else(&ctx, &d),
+            AnyDiagnostic::RemoveTrailingReturn(d) => match handlers::remove_trailing_return::remove_trailing_return(&ctx, &d) {
+                Some(it) => it,
+                None => continue,
+            },
+            AnyDiagnostic::RemoveUnnecessaryElse(d) => match handlers::remove_unnecessary_else::remove_unnecessary_else(&ctx, &d) {
+                Some(it) => it,
+                None => continue,
+            },
         };
         res.push(d)
     }
@@ -399,9 +413,9 @@ pub fn diagnostics(
         .iter_mut()
         .filter_map(|it| {
             Some((
-                it.main_node
-                    .map(|ptr| ptr.map(|node| node.to_node(&ctx.sema.parse_or_expand(ptr.file_id))))
-                    .clone()?,
+                it.main_node.map(|ptr| {
+                    ptr.map(|node| node.to_node(&ctx.sema.parse_or_expand(ptr.file_id)))
+                })?,
                 it,
             ))
         })
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
index dcaa2120892..bb5c2b79139 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
@@ -283,6 +283,10 @@ fn test_disabled_diagnostics() {
 
 #[test]
 fn minicore_smoke_test() {
+    if test_utils::skip_slow_tests() {
+        return;
+    }
+
     fn check(minicore: MiniCore) {
         let source = minicore.source_code();
         let mut config = DiagnosticsConfig::test_sample();
diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml
index aca7d613e11..a535015a27f 100644
--- a/src/tools/rust-analyzer/crates/ide/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml
@@ -36,6 +36,7 @@ ide-ssr.workspace = true
 profile.workspace = true
 stdx.workspace = true
 syntax.workspace = true
+span.workspace = true
 text-edit.workspace = true
 # ide should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index d10bdca50d8..64b4ccc5bd8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -5,8 +5,6 @@ mod tests;
 
 mod intra_doc_links;
 
-use std::ffi::OsStr;
-
 use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
 use pulldown_cmark_to_cmark::{cmark_resume_with_options, Options as CMarkOptions};
 use stdx::format_to;
@@ -134,8 +132,8 @@ pub(crate) fn remove_links(markdown: &str) -> String {
 pub(crate) fn external_docs(
     db: &RootDatabase,
     FilePosition { file_id, offset }: FilePosition,
-    target_dir: Option<&OsStr>,
-    sysroot: Option<&OsStr>,
+    target_dir: Option<&str>,
+    sysroot: Option<&str>,
 ) -> Option<DocumentationLinks> {
     let sema = &Semantics::new(db);
     let file = sema.parse(file_id).syntax().clone();
@@ -331,8 +329,8 @@ fn broken_link_clone_cb(link: BrokenLink<'_>) -> Option<(CowStr<'_>, CowStr<'_>)
 fn get_doc_links(
     db: &RootDatabase,
     def: Definition,
-    target_dir: Option<&OsStr>,
-    sysroot: Option<&OsStr>,
+    target_dir: Option<&str>,
+    sysroot: Option<&str>,
 ) -> DocumentationLinks {
     let join_url = |base_url: Option<Url>, path: &str| -> Option<Url> {
         base_url.and_then(|url| url.join(path).ok())
@@ -479,15 +477,13 @@ fn map_links<'e>(
 fn get_doc_base_urls(
     db: &RootDatabase,
     def: Definition,
-    target_dir: Option<&OsStr>,
-    sysroot: Option<&OsStr>,
+    target_dir: Option<&str>,
+    sysroot: Option<&str>,
 ) -> (Option<Url>, Option<Url>) {
     let local_doc = target_dir
-        .and_then(|path| path.to_str())
         .and_then(|path| Url::parse(&format!("file:///{path}/")).ok())
         .and_then(|it| it.join("doc/").ok());
     let system_doc = sysroot
-        .and_then(|it| it.to_str())
         .map(|sysroot| format!("file:///{sysroot}/share/doc/rust/html/"))
         .and_then(|it| Url::parse(&it).ok());
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
index 60e8d29a716..ac44908a902 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
@@ -1,4 +1,4 @@
-use std::{ffi::OsStr, iter};
+use std::iter;
 
 use expect_test::{expect, Expect};
 use hir::Semantics;
@@ -18,10 +18,10 @@ use crate::{
 
 fn check_external_docs(
     ra_fixture: &str,
-    target_dir: Option<&OsStr>,
+    target_dir: Option<&str>,
     expect_web_url: Option<Expect>,
     expect_local_url: Option<Expect>,
-    sysroot: Option<&OsStr>,
+    sysroot: Option<&str>,
 ) {
     let (analysis, position) = fixture::position(ra_fixture);
     let links = analysis.external_docs(position, target_dir, sysroot).unwrap();
@@ -127,10 +127,10 @@ fn external_docs_doc_builtin_type() {
 //- /main.rs crate:foo
 let x: u3$02 = 0;
 "#,
-        Some(OsStr::new("/home/user/project")),
+        Some("/home/user/project"),
         Some(expect![[r#"https://doc.rust-lang.org/nightly/core/primitive.u32.html"#]]),
         Some(expect![[r#"file:///sysroot/share/doc/rust/html/core/primitive.u32.html"#]]),
-        Some(OsStr::new("/sysroot")),
+        Some("/sysroot"),
     );
 }
 
@@ -143,10 +143,10 @@ use foo$0::Foo;
 //- /lib.rs crate:foo
 pub struct Foo;
 "#,
-        Some(OsStr::new("/home/user/project")),
+        Some("/home/user/project"),
         Some(expect![[r#"https://docs.rs/foo/*/foo/index.html"#]]),
         Some(expect![[r#"file:///home/user/project/doc/foo/index.html"#]]),
-        Some(OsStr::new("/sysroot")),
+        Some("/sysroot"),
     );
 }
 
@@ -157,10 +157,10 @@ fn external_docs_doc_url_std_crate() {
 //- /main.rs crate:std
 use self$0;
 "#,
-        Some(OsStr::new("/home/user/project")),
+        Some("/home/user/project"),
         Some(expect!["https://doc.rust-lang.org/stable/std/index.html"]),
         Some(expect!["file:///sysroot/share/doc/rust/html/std/index.html"]),
-        Some(OsStr::new("/sysroot")),
+        Some("/sysroot"),
     );
 }
 
@@ -171,10 +171,10 @@ fn external_docs_doc_url_struct() {
 //- /main.rs crate:foo
 pub struct Fo$0o;
 "#,
-        Some(OsStr::new("/home/user/project")),
+        Some("/home/user/project"),
         Some(expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]]),
         Some(expect![[r#"file:///home/user/project/doc/foo/struct.Foo.html"#]]),
-        Some(OsStr::new("/sysroot")),
+        Some("/sysroot"),
     );
 }
 
@@ -185,10 +185,10 @@ fn external_docs_doc_url_windows_backslash_path() {
 //- /main.rs crate:foo
 pub struct Fo$0o;
 "#,
-        Some(OsStr::new(r"C:\Users\user\project")),
+        Some(r"C:\Users\user\project"),
         Some(expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]]),
         Some(expect![[r#"file:///C:/Users/user/project/doc/foo/struct.Foo.html"#]]),
-        Some(OsStr::new("/sysroot")),
+        Some("/sysroot"),
     );
 }
 
@@ -199,10 +199,10 @@ fn external_docs_doc_url_windows_slash_path() {
 //- /main.rs crate:foo
 pub struct Fo$0o;
 "#,
-        Some(OsStr::new(r"C:/Users/user/project")),
+        Some("C:/Users/user/project"),
         Some(expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]]),
         Some(expect![[r#"file:///C:/Users/user/project/doc/foo/struct.Foo.html"#]]),
-        Some(OsStr::new("/sysroot")),
+        Some("/sysroot"),
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
index 0e790e14205..813691540f9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
@@ -134,15 +134,22 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
                 if let Some(type_param_list) = it.generic_param_list() {
                     collapse_ws(type_param_list.syntax(), &mut detail);
                 }
-                if let Some(param_list) = it.param_list() {
+                let has_self_param = if let Some(param_list) = it.param_list() {
                     collapse_ws(param_list.syntax(), &mut detail);
-                }
+                    param_list.self_param().is_some()
+                } else {
+                    false
+                };
                 if let Some(ret_type) = it.ret_type() {
                     detail.push(' ');
                     collapse_ws(ret_type.syntax(), &mut detail);
                 }
 
-                decl_with_detail(&it, Some(detail), StructureNodeKind::SymbolKind(SymbolKind::Function))
+                decl_with_detail(&it, Some(detail), StructureNodeKind::SymbolKind(if has_self_param {
+                    SymbolKind::Method
+                } else {
+                    SymbolKind::Function
+                }))
             },
             ast::Struct(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Struct)),
             ast::Union(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Union)),
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
index 8a12cbacccc..76e5e9dd928 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
@@ -340,4 +340,75 @@ impl Tr for S {
 "#,
         );
     }
+
+    #[test]
+    fn goto_adt_implementation_inside_block() {
+        check(
+            r#"
+//- minicore: copy, derive
+trait Bar {}
+
+fn test() {
+    #[derive(Copy)]
+  //^^^^^^^^^^^^^^^
+    struct Foo$0;
+
+    impl Foo {}
+       //^^^
+
+    trait Baz {}
+
+    impl Bar for Foo {}
+               //^^^
+
+    impl Baz for Foo {}
+               //^^^
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_trait_implementation_inside_block() {
+        check(
+            r#"
+struct Bar;
+
+fn test() {
+    trait Foo$0 {}
+
+    struct Baz;
+
+    impl Foo for Bar {}
+               //^^^
+
+    impl Foo for Baz {}
+               //^^^
+}
+"#,
+        );
+        check(
+            r#"
+struct Bar;
+
+fn test() {
+    trait Foo {
+        fn foo$0() {}
+    }
+
+    struct Baz;
+
+    impl Foo for Bar {
+        fn foo() {}
+         //^^^
+    }
+
+    impl Foo for Baz {
+        fn foo() {}
+         //^^^
+    }
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 8f4c629b581..822751c0e4c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -33,6 +33,7 @@ pub struct HoverConfig {
     pub keywords: bool,
     pub format: HoverDocFormat,
     pub max_trait_assoc_items_count: Option<usize>,
+    pub max_struct_field_count: Option<usize>,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 63777d49105..abedbff831a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -410,6 +410,9 @@ pub(super) fn definition(
         Definition::Trait(trait_) => {
             trait_.display_limited(db, config.max_trait_assoc_items_count).to_string()
         }
+        Definition::Adt(Adt::Struct(struct_)) => {
+            struct_.display_limited(db, config.max_struct_field_count).to_string()
+        }
         _ => def.label(db),
     };
     let docs = def.docs(db, famous_defs);
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 4451e31870f..08925fcdff5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -18,6 +18,7 @@ const HOVER_BASE_CONFIG: HoverConfig = HoverConfig {
     format: HoverDocFormat::Markdown,
     keywords: true,
     max_trait_assoc_items_count: None,
+    max_struct_field_count: None,
 };
 
 fn check_hover_no_result(ra_fixture: &str) {
@@ -50,6 +51,28 @@ fn check(ra_fixture: &str, expect: Expect) {
 }
 
 #[track_caller]
+fn check_hover_struct_limit(count: usize, ra_fixture: &str, expect: Expect) {
+    let (analysis, position) = fixture::position(ra_fixture);
+    let hover = analysis
+        .hover(
+            &HoverConfig {
+                links_in_hover: true,
+                max_struct_field_count: Some(count),
+                ..HOVER_BASE_CONFIG
+            },
+            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
+        )
+        .unwrap()
+        .unwrap();
+
+    let content = analysis.db.file_text(position.file_id);
+    let hovered_element = &content[hover.range];
+
+    let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup);
+    expect.assert_eq(&actual)
+}
+
+#[track_caller]
 fn check_assoc_count(count: usize, ra_fixture: &str, expect: Expect) {
     let (analysis, position) = fixture::position(ra_fixture);
     let hover = analysis
@@ -853,9 +876,7 @@ struct Foo$0 { field: u32 }
 
             ```rust
             // size = 4, align = 4
-            struct Foo {
-                field: u32,
-            }
+            struct Foo
             ```
         "#]],
     );
@@ -875,8 +896,74 @@ struct Foo$0 where u32: Copy { field: u32 }
             struct Foo
             where
                 u32: Copy,
-            {
-                field: u32,
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn hover_record_struct_limit() {
+    check_hover_struct_limit(
+        3,
+        r#"
+    struct Foo$0 { a: u32, b: i32, c: i32 }
+    "#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4
+            struct Foo  {
+                a: u32,
+                b: i32,
+                c: i32,
+            }
+            ```
+        "#]],
+    );
+    check_hover_struct_limit(
+        3,
+        r#"
+    struct Foo$0 { a: u32 }
+    "#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 4, align = 4
+            struct Foo  {
+                a: u32,
+            }
+            ```
+        "#]],
+    );
+    check_hover_struct_limit(
+        3,
+        r#"
+    struct Foo$0 { a: u32, b: i32, c: i32, d: u32 }
+    "#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 16 (0x10), align = 4
+            struct Foo  {
+                a: u32,
+                b: i32,
+                c: i32,
+                /* … */
             }
             ```
         "#]],
@@ -1344,9 +1431,7 @@ impl Thing {
                 ```
 
                 ```rust
-                struct Thing {
-                    x: u32,
-                }
+                struct Thing
                 ```
             "#]],
     );
@@ -1365,9 +1450,7 @@ impl Thing {
                 ```
 
                 ```rust
-                struct Thing {
-                    x: u32,
-                }
+                struct Thing
                 ```
             "#]],
     );
@@ -2599,7 +2682,7 @@ fn main() { let s$0t = S{ f1:0 }; }
                                     focus_range: 7..8,
                                     name: "S",
                                     kind: Struct,
-                                    description: "struct S {\n    f1: u32,\n}",
+                                    description: "struct S",
                                 },
                             },
                         ],
@@ -2645,7 +2728,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; }
                                 focus_range: 24..25,
                                 name: "S",
                                 kind: Struct,
-                                description: "struct S<T> {\n    f1: T,\n}",
+                                description: "struct S<T>",
                             },
                         },
                     ],
@@ -2704,7 +2787,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
                                 focus_range: 24..25,
                                 name: "S",
                                 kind: Struct,
-                                description: "struct S<T> {\n    f1: T,\n}",
+                                description: "struct S<T>",
                             },
                         },
                     ],
@@ -2957,7 +3040,7 @@ fn main() { let s$0t = foo(); }
                                 focus_range: 39..41,
                                 name: "S1",
                                 kind: Struct,
-                                description: "struct S1 {}",
+                                description: "struct S1",
                             },
                         },
                         HoverGotoTypeData {
@@ -2970,7 +3053,7 @@ fn main() { let s$0t = foo(); }
                                 focus_range: 52..54,
                                 name: "S2",
                                 kind: Struct,
-                                description: "struct S2 {}",
+                                description: "struct S2",
                             },
                         },
                     ],
@@ -3061,7 +3144,7 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {}
                                 focus_range: 36..37,
                                 name: "S",
                                 kind: Struct,
-                                description: "struct S {}",
+                                description: "struct S",
                             },
                         },
                     ],
@@ -3161,7 +3244,7 @@ fn foo(ar$0g: &impl Foo<S>) {}
                                 focus_range: 23..24,
                                 name: "S",
                                 kind: Struct,
-                                description: "struct S {}",
+                                description: "struct S",
                             },
                         },
                     ],
@@ -3198,7 +3281,7 @@ fn main() { let s$0t = foo(); }
                                 focus_range: 49..50,
                                 name: "B",
                                 kind: Struct,
-                                description: "struct B<T> {}",
+                                description: "struct B<T>",
                             },
                         },
                         HoverGotoTypeData {
@@ -3287,7 +3370,7 @@ fn foo(ar$0g: &dyn Foo<S>) {}
                                 focus_range: 23..24,
                                 name: "S",
                                 kind: Struct,
-                                description: "struct S {}",
+                                description: "struct S",
                             },
                         },
                     ],
@@ -3322,7 +3405,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
                                 focus_range: 50..51,
                                 name: "B",
                                 kind: Struct,
-                                description: "struct B<T> {}",
+                                description: "struct B<T>",
                             },
                         },
                         HoverGotoTypeData {
@@ -3361,7 +3444,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
                                 focus_range: 65..66,
                                 name: "S",
                                 kind: Struct,
-                                description: "struct S {}",
+                                description: "struct S",
                             },
                         },
                     ],
@@ -5106,6 +5189,32 @@ fn foo(e: E) {
 }
 
 #[test]
+fn hover_const_value() {
+    check(
+        r#"
+pub enum AA {
+    BB,
+}
+const CONST: AA = AA::BB;
+pub fn the_function() -> AA {
+    CON$0ST
+}
+"#,
+        expect![[r#"
+            *CONST*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            const CONST: AA = BB
+            ```
+        "#]],
+    );
+}
+
+#[test]
 fn array_repeat_exp() {
     check(
         r#"
@@ -7747,3 +7856,25 @@ impl Iterator for S {
         "#]],
     );
 }
+
+#[test]
+fn hover_lifetime_regression_16963() {
+    check(
+        r#"
+struct Pedro$0<'a> {
+    hola: &'a str
+}
+"#,
+        expect![[r#"
+            *Pedro*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            struct Pedro<'a>
+            ```
+        "#]],
+    )
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 8311e770b4b..dda38ce77e0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -1,5 +1,6 @@
 use std::{
     fmt::{self, Write},
+    hash::{BuildHasher, BuildHasherDefault},
     mem::take,
 };
 
@@ -8,7 +9,7 @@ use hir::{
     known, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef,
     ModuleDefId, Semantics,
 };
-use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase};
+use ide_db::{base_db::FileRange, famous_defs::FamousDefs, FxHasher, RootDatabase};
 use itertools::Itertools;
 use smallvec::{smallvec, SmallVec};
 use stdx::never;
@@ -116,7 +117,7 @@ pub enum AdjustmentHintsMode {
     PreferPostfix,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum InlayKind {
     Adjustment,
     BindingMode,
@@ -132,7 +133,7 @@ pub enum InlayKind {
     RangeExclusive,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Hash)]
 pub enum InlayHintPosition {
     Before,
     After,
@@ -151,13 +152,23 @@ pub struct InlayHint {
     pub label: InlayHintLabel,
     /// Text edit to apply when "accepting" this inlay hint.
     pub text_edit: Option<TextEdit>,
-    pub needs_resolve: bool,
+}
+
+impl std::hash::Hash for InlayHint {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.range.hash(state);
+        self.position.hash(state);
+        self.pad_left.hash(state);
+        self.pad_right.hash(state);
+        self.kind.hash(state);
+        self.label.hash(state);
+        self.text_edit.is_some().hash(state);
+    }
 }
 
 impl InlayHint {
     fn closing_paren_after(kind: InlayKind, range: TextRange) -> InlayHint {
         InlayHint {
-            needs_resolve: false,
             range,
             kind,
             label: InlayHintLabel::from(")"),
@@ -167,9 +178,9 @@ impl InlayHint {
             pad_right: false,
         }
     }
+
     fn opening_paren_before(kind: InlayKind, range: TextRange) -> InlayHint {
         InlayHint {
-            needs_resolve: false,
             range,
             kind,
             label: InlayHintLabel::from("("),
@@ -179,15 +190,19 @@ impl InlayHint {
             pad_right: false,
         }
     }
+
+    pub fn needs_resolve(&self) -> bool {
+        self.text_edit.is_some() || self.label.needs_resolve()
+    }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Hash)]
 pub enum InlayTooltip {
     String(String),
     Markdown(String),
 }
 
-#[derive(Default)]
+#[derive(Default, Hash)]
 pub struct InlayHintLabel {
     pub parts: SmallVec<[InlayHintLabelPart; 1]>,
 }
@@ -265,6 +280,7 @@ impl fmt::Debug for InlayHintLabel {
     }
 }
 
+#[derive(Hash)]
 pub struct InlayHintLabelPart {
     pub text: String,
     /// Source location represented by this label part. The client will use this to fetch the part's
@@ -313,9 +329,7 @@ impl fmt::Write for InlayHintLabelBuilder<'_> {
 
 impl HirWrite for InlayHintLabelBuilder<'_> {
     fn start_location_link(&mut self, def: ModuleDefId) {
-        if self.location.is_some() {
-            never!("location link is already started");
-        }
+        never!(self.location.is_some(), "location link is already started");
         self.make_new_part();
         let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
         let location = location.call_site();
@@ -425,11 +439,6 @@ fn ty_to_text_edit(
     Some(builder.finish())
 }
 
-pub enum RangeLimit {
-    Fixed(TextRange),
-    NearestParent(TextSize),
-}
-
 // Feature: Inlay Hints
 //
 // rust-analyzer shows additional information inline with the source code.
@@ -451,7 +460,7 @@ pub enum RangeLimit {
 pub(crate) fn inlay_hints(
     db: &RootDatabase,
     file_id: FileId,
-    range_limit: Option<RangeLimit>,
+    range_limit: Option<TextRange>,
     config: &InlayHintsConfig,
 ) -> Vec<InlayHint> {
     let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered();
@@ -466,31 +475,13 @@ pub(crate) fn inlay_hints(
 
         let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
         match range_limit {
-            Some(RangeLimit::Fixed(range)) => match file.covering_element(range) {
+            Some(range) => match file.covering_element(range) {
                 NodeOrToken::Token(_) => return acc,
                 NodeOrToken::Node(n) => n
                     .descendants()
                     .filter(|descendant| range.intersect(descendant.text_range()).is_some())
                     .for_each(hints),
             },
-            Some(RangeLimit::NearestParent(position)) => {
-                match file.token_at_offset(position).left_biased() {
-                    Some(token) => {
-                        if let Some(parent_block) =
-                            token.parent_ancestors().find_map(ast::BlockExpr::cast)
-                        {
-                            parent_block.syntax().descendants().for_each(hints)
-                        } else if let Some(parent_item) =
-                            token.parent_ancestors().find_map(ast::Item::cast)
-                        {
-                            parent_item.syntax().descendants().for_each(hints)
-                        } else {
-                            return acc;
-                        }
-                    }
-                    None => return acc,
-                }
-            }
             None => file.descendants().for_each(hints),
         };
     }
@@ -498,6 +489,39 @@ pub(crate) fn inlay_hints(
     acc
 }
 
+pub(crate) fn inlay_hints_resolve(
+    db: &RootDatabase,
+    file_id: FileId,
+    position: TextSize,
+    hash: u64,
+    config: &InlayHintsConfig,
+) -> Option<InlayHint> {
+    let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered();
+    let sema = Semantics::new(db);
+    let file = sema.parse(file_id);
+    let file = file.syntax();
+
+    let scope = sema.scope(file)?;
+    let famous_defs = FamousDefs(&sema, scope.krate());
+    let mut acc = Vec::new();
+
+    let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
+    match file.token_at_offset(position).left_biased() {
+        Some(token) => {
+            if let Some(parent_block) = token.parent_ancestors().find_map(ast::BlockExpr::cast) {
+                parent_block.syntax().descendants().for_each(hints)
+            } else if let Some(parent_item) = token.parent_ancestors().find_map(ast::Item::cast) {
+                parent_item.syntax().descendants().for_each(hints)
+            } else {
+                return None;
+            }
+        }
+        None => return None,
+    }
+
+    acc.into_iter().find(|hint| BuildHasherDefault::<FxHasher>::default().hash_one(hint) == hash)
+}
+
 fn hints(
     hints: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index 631807d99a7..20128a286f2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
@@ -147,7 +147,6 @@ pub(super) fn hints(
             None,
         );
         acc.push(InlayHint {
-            needs_resolve: label.needs_resolve(),
             range: expr.syntax().text_range(),
             pad_left: false,
             pad_right: false,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index 45b51e35570..07b9f9cc1ff 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -99,7 +99,6 @@ pub(super) fn hints(
         None => pat.syntax().text_range(),
     };
     acc.push(InlayHint {
-        needs_resolve: label.needs_resolve() || text_edit.is_some(),
         range: match type_ascriptable {
             Some(Some(t)) => text_range.cover(t.text_range()),
             _ => text_range,
@@ -177,11 +176,7 @@ mod tests {
     use syntax::{TextRange, TextSize};
     use test_utils::extract_annotations;
 
-    use crate::{
-        fixture,
-        inlay_hints::{InlayHintsConfig, RangeLimit},
-        ClosureReturnTypeHints,
-    };
+    use crate::{fixture, inlay_hints::InlayHintsConfig, ClosureReturnTypeHints};
 
     use crate::inlay_hints::tests::{
         check, check_edit, check_no_edit, check_with_config, DISABLED_CONFIG, TEST_CONFIG,
@@ -404,7 +399,7 @@ fn main() {
             .inlay_hints(
                 &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
                 file_id,
-                Some(RangeLimit::Fixed(TextRange::new(TextSize::from(500), TextSize::from(600)))),
+                Some(TextRange::new(TextSize::from(500), TextSize::from(600))),
             )
             .unwrap();
         let actual =
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
index 35504ffa785..f27390ee898 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
@@ -50,7 +50,6 @@ pub(super) fn hints(
             _ => return,
         };
         acc.push(InlayHint {
-            needs_resolve: false,
             range,
             kind: InlayKind::BindingMode,
             label: r.into(),
@@ -69,7 +68,6 @@ pub(super) fn hints(
                 hir::BindingMode::Ref(Mutability::Shared) => "ref",
             };
             acc.push(InlayHint {
-                needs_resolve: false,
                 range: pat.syntax().text_range(),
                 kind: InlayKind::BindingMode,
                 label: bm.into(),
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index b6063978e92..d86487d4b41 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -59,7 +59,6 @@ pub(super) fn hints(
             }
             let label = label_of_ty(famous_defs, config, &ty)?;
             acc.push(InlayHint {
-                needs_resolve: label.needs_resolve(),
                 range: expr.syntax().text_range(),
                 kind: InlayKind::Chaining,
                 label,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
index 2b68538c198..2cefd5acdc2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
@@ -109,7 +109,6 @@ pub(super) fn hints(
 
     let linked_location = name_range.map(|range| FileRange { file_id, range });
     acc.push(InlayHint {
-        needs_resolve: linked_location.is_some(),
         range: closing_token.text_range(),
         kind: InlayKind::ClosingBrace,
         label: InlayHintLabel::simple(label, None, linked_location),
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
index 2f8b959516d..f1b524e0880 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
@@ -32,7 +32,6 @@ pub(super) fn hints(
             let range = closure.syntax().first_token()?.prev_token()?.text_range();
             let range = TextRange::new(range.end() - TextSize::from(1), range.end());
             acc.push(InlayHint {
-                needs_resolve: false,
                 range,
                 kind: InlayKind::ClosureCapture,
                 label: InlayHintLabel::from("move"),
@@ -45,7 +44,6 @@ pub(super) fn hints(
         }
     };
     acc.push(InlayHint {
-        needs_resolve: false,
         range: move_kw_range,
         kind: InlayKind::ClosureCapture,
         label: InlayHintLabel::from("("),
@@ -79,7 +77,6 @@ pub(super) fn hints(
             }),
         );
         acc.push(InlayHint {
-            needs_resolve: label.needs_resolve(),
             range: move_kw_range,
             kind: InlayKind::ClosureCapture,
             label,
@@ -91,7 +88,6 @@ pub(super) fn hints(
 
         if idx != last {
             acc.push(InlayHint {
-                needs_resolve: false,
                 range: move_kw_range,
                 kind: InlayKind::ClosureCapture,
                 label: InlayHintLabel::from(", "),
@@ -103,7 +99,6 @@ pub(super) fn hints(
         }
     }
     acc.push(InlayHint {
-        needs_resolve: false,
         range: move_kw_range,
         kind: InlayKind::ClosureCapture,
         label: InlayHintLabel::from(")"),
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
index 204967cd7ca..3b41db0f13d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
@@ -64,7 +64,6 @@ pub(super) fn hints(
     };
 
     acc.push(InlayHint {
-        needs_resolve: label.needs_resolve() || text_edit.is_some(),
         range: param_list.syntax().text_range(),
         kind: InlayKind::Type,
         label,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
index 06cce147d2a..202954100fb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
@@ -79,7 +79,6 @@ fn variant_hints(
         None,
     );
     acc.push(InlayHint {
-        needs_resolve: label.needs_resolve(),
         range: match eq_token {
             Some(t) => range.cover(t.text_range()),
             _ => range,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
index 6e5f23bed09..d3666754e2b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
@@ -22,7 +22,6 @@ pub(super) fn hints(
     }
 
     let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint {
-        needs_resolve: false,
         range: t.text_range(),
         kind: InlayKind::Lifetime,
         label: label.into(),
@@ -184,7 +183,6 @@ pub(super) fn hints(
             let angle_tok = gpl.l_angle_token()?;
             let is_empty = gpl.generic_params().next().is_none();
             acc.push(InlayHint {
-                needs_resolve: false,
                 range: angle_tok.text_range(),
                 kind: InlayKind::Lifetime,
                 label: format!(
@@ -200,7 +198,6 @@ pub(super) fn hints(
             });
         }
         (None, allocated_lifetimes) => acc.push(InlayHint {
-            needs_resolve: false,
             range: func.name()?.syntax().text_range(),
             kind: InlayKind::GenericParamList,
             label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(),
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 5ba4e514e1f..31f0c790374 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
@@ -105,7 +105,6 @@ pub(super) fn hints(
                 pad_left: true,
                 pad_right: true,
                 kind: InlayKind::Drop,
-                needs_resolve: label.needs_resolve(),
                 label,
                 text_edit: None,
             })
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
index f18e6421cbc..42223ddf580 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
@@ -31,7 +31,6 @@ pub(super) fn hints(
         if ty.lifetime().is_none() {
             let t = ty.amp_token()?;
             acc.push(InlayHint {
-                needs_resolve: false,
                 range: t.text_range(),
                 kind: InlayKind::Lifetime,
                 label: "'static".into(),
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index 418fc002a8b..96e845b2f32 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -57,7 +57,6 @@ pub(super) fn hints(
             let label =
                 InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location);
             InlayHint {
-                needs_resolve: label.needs_resolve(),
                 range,
                 kind: InlayKind::Parameter,
                 label,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
index c4b0c199fc2..bfb92838857 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
@@ -30,7 +30,6 @@ fn inlay_hint(token: SyntaxToken) -> InlayHint {
         kind: crate::InlayKind::RangeExclusive,
         label: crate::InlayHintLabel::from("<"),
         text_edit: None,
-        needs_resolve: false,
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 6955e14a10a..ad48d803895 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -58,8 +58,6 @@ mod view_item_tree;
 mod view_memory_layout;
 mod view_mir;
 
-use std::ffi::OsStr;
-
 use cfg::CfgOptions;
 use fetch_crates::CrateInfo;
 use hir::ChangeWithProcMacros;
@@ -90,7 +88,7 @@ pub use crate::{
     inlay_hints::{
         AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
         InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition,
-        InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints, RangeLimit,
+        InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
@@ -121,8 +119,8 @@ pub use ide_completion::{
 };
 pub use ide_db::{
     base_db::{
-        Cancelled, CrateGraph, CrateId, Edition, FileChange, FileId, FilePosition, FileRange,
-        SourceRoot, SourceRootId,
+        Cancelled, CrateGraph, CrateId, FileChange, FileId, FilePosition, FileRange, SourceRoot,
+        SourceRootId,
     },
     documentation::Documentation,
     label::Label,
@@ -137,6 +135,7 @@ pub use ide_diagnostics::{
     Diagnostic, DiagnosticCode, DiagnosticsConfig, ExprFillDefaultMode, Severity,
 };
 pub use ide_ssr::SsrError;
+pub use span::Edition;
 pub use syntax::{TextRange, TextSize};
 pub use text_edit::{Indel, TextEdit};
 
@@ -354,6 +353,10 @@ impl Analysis {
         self.with_db(|db| test_explorer::discover_tests_in_crate(db, crate_id))
     }
 
+    pub fn discover_tests_in_file(&self, file_id: FileId) -> Cancellable<Vec<TestItem>> {
+        self.with_db(|db| test_explorer::discover_tests_in_file(db, file_id))
+    }
+
     /// Renders the crate graph to GraphViz "dot" syntax.
     pub fn view_crate_graph(&self, full: bool) -> Cancellable<Result<String, String>> {
         self.with_db(|db| view_crate_graph::view_crate_graph(db, full))
@@ -415,10 +418,19 @@ impl Analysis {
         &self,
         config: &InlayHintsConfig,
         file_id: FileId,
-        range: Option<RangeLimit>,
+        range: Option<TextRange>,
     ) -> Cancellable<Vec<InlayHint>> {
         self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config))
     }
+    pub fn inlay_hints_resolve(
+        &self,
+        config: &InlayHintsConfig,
+        file_id: FileId,
+        position: TextSize,
+        hash: u64,
+    ) -> Cancellable<Option<InlayHint>> {
+        self.with_db(|db| inlay_hints::inlay_hints_resolve(db, file_id, position, hash, config))
+    }
 
     /// Returns the set of folding ranges.
     pub fn folding_ranges(&self, file_id: FileId) -> Cancellable<Vec<Fold>> {
@@ -502,8 +514,8 @@ impl Analysis {
     pub fn external_docs(
         &self,
         position: FilePosition,
-        target_dir: Option<&OsStr>,
-        sysroot: Option<&OsStr>,
+        target_dir: Option<&str>,
+        sysroot: Option<&str>,
     ) -> Cancellable<doc_links::DocumentationLinks> {
         self.with_db(|db| {
             doc_links::external_docs(db, position, target_dir, sysroot).unwrap_or_default()
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index fe063081f79..3fef16df25e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -167,6 +167,7 @@ impl StaticIndex<'_> {
             keywords: true,
             format: crate::HoverDocFormat::Markdown,
             max_trait_assoc_items_count: None,
+            max_struct_field_count: None,
         };
         let tokens = tokens.filter(|token| {
             matches!(
diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs
index c3d85e38936..8e7767c8e5d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/status.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/status.rs
@@ -10,7 +10,7 @@ use ide_db::{
             debug::{DebugQueryTable, TableEntry},
             Query, QueryTable,
         },
-        CrateData, FileId, FileTextQuery, ParseQuery, SourceDatabase, SourceRootId,
+        CompressedFileTextQuery, CrateData, FileId, ParseQuery, SourceDatabase, SourceRootId,
     },
     symbol_index::ModuleSymbolsQuery,
 };
@@ -38,7 +38,7 @@ use triomphe::Arc;
 pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
     let mut buf = String::new();
 
-    format_to!(buf, "{}\n", collect_query(FileTextQuery.in_db(db)));
+    format_to!(buf, "{}\n", collect_query(CompressedFileTextQuery.in_db(db)));
     format_to!(buf, "{}\n", collect_query(ParseQuery.in_db(db)));
     format_to!(buf, "{}\n", collect_query(ParseMacroExpansionQuery.in_db(db)));
     format_to!(buf, "{}\n", collect_query(LibrarySymbolsQuery.in_db(db)));
@@ -160,7 +160,7 @@ impl QueryCollect for ParseMacroExpansionQuery {
     type Collector = SyntaxTreeStats<true>;
 }
 
-impl QueryCollect for FileTextQuery {
+impl QueryCollect for CompressedFileTextQuery {
     type Collector = FilesStats;
 }
 
@@ -188,8 +188,8 @@ impl fmt::Display for FilesStats {
     }
 }
 
-impl StatCollect<FileId, Arc<str>> for FilesStats {
-    fn collect_entry(&mut self, _: FileId, value: Option<Arc<str>>) {
+impl StatCollect<FileId, Arc<[u8]>> for FilesStats {
+    fn collect_entry(&mut self, _: FileId, value: Option<Arc<[u8]>>) {
         self.total += 1;
         self.size += value.unwrap().len();
     }
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 96c7c475594..e7346cbb992 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
@@ -178,6 +178,23 @@ fn keyword(
         T![do] | T![yeet] if parent_matches::<ast::YeetExpr>(&token) => h | HlMod::ControlFlow,
         T![for] if parent_matches::<ast::ForExpr>(&token) => h | HlMod::ControlFlow,
         T![unsafe] => h | HlMod::Unsafe,
+        T![const]
+            if token.parent().map_or(false, |it| {
+                matches!(
+                    it.kind(),
+                    SyntaxKind::CONST
+                        | SyntaxKind::FN
+                        | SyntaxKind::IMPL
+                        | SyntaxKind::BLOCK_EXPR
+                        | SyntaxKind::CLOSURE_EXPR
+                        | SyntaxKind::FN_PTR_TYPE
+                        | SyntaxKind::TYPE_BOUND
+                        | SyntaxKind::CONST_BLOCK_PAT
+                )
+            }) =>
+        {
+            h | HlMod::Const
+        }
         T![true] | T![false] => HlTag::BoolLiteral.into(),
         // crate is handled just as a token if it's in an `extern crate`
         T![crate] if parent_matches::<ast::ExternCrate>(&token) => h,
@@ -377,14 +394,17 @@ pub(super) fn highlight_def(
             if let Some(item) = func.as_assoc_item(db) {
                 h |= HlMod::Associated;
                 match func.self_param(db) {
-                    Some(sp) => match sp.access(db) {
-                        hir::Access::Exclusive => {
-                            h |= HlMod::Mutable;
-                            h |= HlMod::Reference;
+                    Some(sp) => {
+                        h.tag = HlTag::Symbol(SymbolKind::Method);
+                        match sp.access(db) {
+                            hir::Access::Exclusive => {
+                                h |= HlMod::Mutable;
+                                h |= HlMod::Reference;
+                            }
+                            hir::Access::Shared => h |= HlMod::Reference,
+                            hir::Access::Owned => h |= HlMod::Consuming,
                         }
-                        hir::Access::Shared => h |= HlMod::Reference,
-                        hir::Access::Owned => h |= HlMod::Consuming,
-                    },
+                    }
                     None => h |= HlMod::Static,
                 }
 
@@ -406,6 +426,9 @@ pub(super) fn highlight_def(
             if func.is_async(db) {
                 h |= HlMod::Async;
             }
+            if func.is_const(db) {
+                h |= HlMod::Const;
+            }
 
             h
         }
@@ -420,10 +443,11 @@ pub(super) fn highlight_def(
         }
         Definition::Variant(_) => Highlight::new(HlTag::Symbol(SymbolKind::Variant)),
         Definition::Const(konst) => {
-            let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const));
+            let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)) | HlMod::Const;
 
             if let Some(item) = konst.as_assoc_item(db) {
                 h |= HlMod::Associated;
+                h |= HlMod::Static;
                 match item.container(db) {
                     hir::AssocItemContainer::Impl(i) => {
                         if i.trait_(db).is_some() {
@@ -445,6 +469,7 @@ pub(super) fn highlight_def(
 
             if let Some(item) = type_.as_assoc_item(db) {
                 h |= HlMod::Associated;
+                h |= HlMod::Static;
                 match item.container(db) {
                     hir::AssocItemContainer::Impl(i) => {
                         if i.trait_(db).is_some() {
@@ -474,7 +499,7 @@ pub(super) fn highlight_def(
         Definition::GenericParam(it) => match it {
             hir::GenericParam::TypeParam(_) => Highlight::new(HlTag::Symbol(SymbolKind::TypeParam)),
             hir::GenericParam::ConstParam(_) => {
-                Highlight::new(HlTag::Symbol(SymbolKind::ConstParam))
+                Highlight::new(HlTag::Symbol(SymbolKind::ConstParam)) | HlMod::Const
             }
             hir::GenericParam::LifetimeParam(_) => {
                 Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam))
@@ -550,8 +575,7 @@ fn highlight_method_call(
 ) -> Option<Highlight> {
     let func = sema.resolve_method_call(method_call)?;
 
-    let mut h = SymbolKind::Function.into();
-    h |= HlMod::Associated;
+    let mut h = SymbolKind::Method.into();
 
     if func.is_unsafe_to_call(sema.db) || sema.is_unsafe_method_call(method_call) {
         h |= HlMod::Unsafe;
@@ -647,7 +671,7 @@ fn highlight_name_ref_by_syntax(
     match parent.kind() {
         METHOD_CALL_EXPR => ast::MethodCallExpr::cast(parent)
             .and_then(|it| highlight_method_call(sema, krate, &it))
-            .unwrap_or_else(|| SymbolKind::Function.into()),
+            .unwrap_or_else(|| SymbolKind::Method.into()),
         FIELD_EXPR => {
             let h = HlTag::Symbol(SymbolKind::Field);
             let is_union = ast::FieldExpr::cast(parent)
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
index a6dca0541e5..e754b702dee 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
@@ -109,6 +109,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs
index 5163a0de417..5c7a463ccdc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs
@@ -46,7 +46,7 @@ pub enum HlTag {
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 #[repr(u8)]
 pub enum HlMod {
-    /// Used for items in traits and impls.
+    /// Used for associated items.
     Associated = 0,
     /// Used with keywords like `async` and `await`.
     Async,
@@ -54,6 +54,8 @@ pub enum HlMod {
     Attribute,
     /// Callable item or value.
     Callable,
+    /// Constant operation.
+    Const,
     /// Value that is being consumed in a function call
     Consuming,
     /// Used with keywords like `if` and `break`.
@@ -82,7 +84,7 @@ pub enum HlMod {
     Public,
     /// Immutable reference.
     Reference,
-    /// Used for associated functions.
+    /// Used for associated items, except Methods. (Some languages call these static members)
     Static,
     /// Used for items in traits and trait impls.
     Trait,
@@ -147,6 +149,7 @@ impl HlTag {
                 SymbolKind::LifetimeParam => "lifetime",
                 SymbolKind::Local => "variable",
                 SymbolKind::Macro => "macro",
+                SymbolKind::Method => "method",
                 SymbolKind::ProcMacro => "proc_macro",
                 SymbolKind::Module => "module",
                 SymbolKind::SelfParam => "self_keyword",
@@ -211,6 +214,7 @@ impl HlMod {
         HlMod::Async,
         HlMod::Attribute,
         HlMod::Callable,
+        HlMod::Const,
         HlMod::Consuming,
         HlMod::ControlFlow,
         HlMod::CrateRoot,
@@ -237,6 +241,7 @@ impl HlMod {
             HlMod::Attribute => "attribute",
             HlMod::Callable => "callable",
             HlMod::Consuming => "consuming",
+            HlMod::Const => "const",
             HlMod::ControlFlow => "control",
             HlMod::CrateRoot => "crate_root",
             HlMod::DefaultLibrary => "default_library",
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 6994cb3d5c5..9c7f03fc158 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -50,15 +51,15 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 <span class="keyword">impl</span> <span class="struct">foo</span> <span class="brace">{</span>
     <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function associated declaration public static">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
-    <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function associated declaration public reference">is_not_static</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+    <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="method associated declaration public reference">is_not_static</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
 <span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span>
     <span class="keyword">fn</span> <span class="function associated declaration static trait">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
-    <span class="keyword">fn</span> <span class="function associated declaration reference trait">t_is_not_static</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+    <span class="keyword">fn</span> <span class="method associated declaration reference trait">t_is_not_static</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
 <span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span>
     <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function associated declaration public static trait">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
-    <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function associated declaration public reference trait">is_not_static</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+    <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="method associated declaration public reference trait">is_not_static</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
index dc2d103b581..de902b5137d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -47,7 +48,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute library">rustfmt</span><span class="operator attribute">::</span><span class="tool_module attribute library">skip</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="module attribute crate_root library">proc_macros</span><span class="operator attribute">::</span><span class="attribute attribute library">identity</span><span class="attribute_bracket attribute">]</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Copy</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Default</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="comment documentation">/// This is a doc comment</span>
 <span class="comment">// This is a normal comment</span>
 <span class="comment documentation">/// This is a doc comment</span>
@@ -57,4 +58,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="comment">// This is another normal comment</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Copy</span><span class="comma attribute">,</span> <span class="unresolved_reference attribute">Unresolved</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="comment">// The reason for these being here is to test AttrIds</span>
-<span class="keyword">struct</span> <span class="struct declaration">Foo</span><span class="semicolon">;</span></code></pre>
\ No newline at end of file
+<span class="keyword">enum</span> <span class="enum declaration">Foo</span> <span class="brace">{</span>
+    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="derive_helper attribute default_library library">default</span><span class="attribute_bracket attribute">]</span>
+    <span class="enum_variant declaration">Bar</span>
+<span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
index 093cc2358a6..eed3968a906 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -58,7 +59,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         <span class="unresolved_reference">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">Bar</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
         <span class="keyword">fn</span> <span class="function declaration">func</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
             <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span>
-                <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param declaration">C</span><span class="colon">:</span> <span class="unresolved_reference">usize</span><span class="angle">&gt;</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span>
+                <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="unresolved_reference">usize</span><span class="angle">&gt;</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span>
             <span class="brace">}</span>
         <span class="brace">}</span>
     <span class="brace">}</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
new file mode 100644
index 00000000000..cd6ffc2c3ae
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
@@ -0,0 +1,83 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.function.unsafe    { color: #BC8383; }
+.trait.unsafe       { color: #BC8383; }
+.operator.unsafe    { color: #BC8383; }
+.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
+.keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.proc_macro         { color: #94BFF3; text-decoration: underline; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
+
+.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span>
+    <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
+        <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span>
+    <span class="brace">}</span><span class="semicolon">;</span>
+<span class="brace">}</span>
+<span class="keyword const">const</span> <span class="constant const declaration">CONST_ITEM</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+<span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function const declaration">const_fn</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param const declaration">CONST_PARAM</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="keyword const">const</span> <span class="brace">{</span><span class="brace">}</span><span class="colon">:</span> <span class="keyword">const</span> <span class="keyword">fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span> <span class="keyword">where</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="colon">:</span> <span class="keyword const">const</span> <span class="trait">ConstTrait</span> <span class="brace">{</span>
+    <span class="constant const">CONST_ITEM</span><span class="semicolon">;</span>
+    <span class="const_param const">CONST_PARAM</span><span class="semicolon">;</span>
+    <span class="keyword const">const</span> <span class="brace">{</span>
+        <span class="keyword">const</span> <span class="punctuation">|</span><span class="punctuation">|</span> <span class="brace">{</span><span class="brace">}</span>
+    <span class="brace">}</span>
+    <span class="macro">id</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>
+        <span class="constant const macro">CONST_ITEM</span><span class="semicolon macro">;</span>
+        <span class="const_param const macro">CONST_PARAM</span><span class="semicolon macro">;</span>
+        <span class="keyword const macro">const</span> <span class="brace macro">{</span>
+            <span class="keyword macro">const</span> <span class="punctuation macro">|</span><span class="punctuation macro">|</span> <span class="brace macro">{</span><span class="brace macro">}</span>
+        <span class="brace macro">}</span><span class="semicolon macro">;</span>
+        <span class="operator macro">&</span><span class="keyword macro">raw</span> <span class="keyword macro">const</span> <span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon macro">;</span>
+        <span class="keyword macro">const</span>
+    <span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="brace">}</span>
+<span class="keyword">trait</span> <span class="trait declaration">ConstTrait</span> <span class="brace">{</span>
+    <span class="keyword const">const</span> <span class="constant associated const declaration static trait">ASSOC_CONST</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function associated const declaration static trait">assoc_const_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="brace">}</span>
+<span class="keyword">impl</span> <span class="keyword const">const</span> <span class="trait">ConstTrait</span> <span class="keyword">for</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
+    <span class="keyword const">const</span> <span class="constant associated const declaration static trait">ASSOC_CONST</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function associated const declaration static trait">assoc_const_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="brace">}</span>
+
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">unsafe_deref</span> <span class="brace">{</span>
+    <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
+        <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
+    <span class="brace">}</span><span class="semicolon">;</span>
+<span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
index 154b823fffb..63e1560b921 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -47,7 +48,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root library">foo</span><span class="semicolon">;</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">iter</span><span class="semicolon">;</span>
 
-<span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration public">NINETY_TWO</span><span class="colon">:</span> <span class="builtin_type">u8</span> <span class="operator">=</span> <span class="numeric_literal">92</span><span class="semicolon">;</span>
+<span class="keyword">pub</span> <span class="keyword const">const</span> <span class="constant const declaration public">NINETY_TWO</span><span class="colon">:</span> <span class="builtin_type">u8</span> <span class="operator">=</span> <span class="numeric_literal">92</span><span class="semicolon">;</span>
 
 <span class="keyword">use</span> <span class="module crate_root library">foo</span> <span class="keyword">as</span> <span class="module crate_root declaration library">foooo</span><span class="semicolon">;</span>
 
@@ -56,13 +57,13 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="brace">}</span>
 
 <span class="keyword">mod</span> <span class="module declaration">bar</span> <span class="brace">{</span>
-    <span class="keyword">pub</span><span class="parenthesis">(</span><span class="keyword control">in</span> <span class="keyword crate_root public">super</span><span class="parenthesis">)</span> <span class="keyword">const</span> <span class="constant declaration">FORTY_TWO</span><span class="colon">:</span> <span class="builtin_type">u8</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="semicolon">;</span>
+    <span class="keyword">pub</span><span class="parenthesis">(</span><span class="keyword control">in</span> <span class="keyword crate_root public">super</span><span class="parenthesis">)</span> <span class="keyword const">const</span> <span class="constant const declaration">FORTY_TWO</span><span class="colon">:</span> <span class="builtin_type">u8</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="semicolon">;</span>
 
     <span class="keyword">mod</span> <span class="module declaration">baz</span> <span class="brace">{</span>
-        <span class="keyword">use</span> <span class="keyword">super</span><span class="operator">::</span><span class="keyword crate_root public">super</span><span class="operator">::</span><span class="constant public">NINETY_TWO</span><span class="semicolon">;</span>
+        <span class="keyword">use</span> <span class="keyword">super</span><span class="operator">::</span><span class="keyword crate_root public">super</span><span class="operator">::</span><span class="constant const public">NINETY_TWO</span><span class="semicolon">;</span>
         <span class="keyword">use</span> <span class="keyword crate_root public">crate</span><span class="operator">::</span><span class="module crate_root library">foooo</span><span class="operator">::</span><span class="struct library">Point</span><span class="semicolon">;</span>
 
-        <span class="keyword">pub</span><span class="parenthesis">(</span><span class="keyword control">in</span> <span class="keyword">super</span><span class="operator">::</span><span class="keyword crate_root public">super</span><span class="parenthesis">)</span> <span class="keyword">const</span> <span class="constant declaration">TWENTY_NINE</span><span class="colon">:</span> <span class="builtin_type">u8</span> <span class="operator">=</span> <span class="numeric_literal">29</span><span class="semicolon">;</span>
+        <span class="keyword">pub</span><span class="parenthesis">(</span><span class="keyword control">in</span> <span class="keyword">super</span><span class="operator">::</span><span class="keyword crate_root public">super</span><span class="parenthesis">)</span> <span class="keyword const">const</span> <span class="constant const declaration">TWENTY_NINE</span><span class="colon">:</span> <span class="builtin_type">u8</span> <span class="operator">=</span> <span class="numeric_literal">29</span><span class="semicolon">;</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
 </code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
index 58613bf1510..366895ce7ec 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -48,5 +49,5 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
     <span class="keyword">let</span> <span class="variable declaration">foo</span> <span class="operator">=</span> <span class="enum_variant default_library library">Some</span><span class="parenthesis">(</span><span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="keyword">let</span> <span class="variable declaration">nums</span> <span class="operator">=</span> <span class="module default_library library">iter</span><span class="operator">::</span><span class="function default_library library">repeat</span><span class="parenthesis">(</span><span class="variable">foo</span><span class="operator">.</span><span class="function associated consuming default_library library">unwrap</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration">nums</span> <span class="operator">=</span> <span class="module default_library library">iter</span><span class="operator">::</span><span class="function default_library library">repeat</span><span class="parenthesis">(</span><span class="variable">foo</span><span class="operator">.</span><span class="method consuming default_library library">unwrap</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
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 34274932afc..b2ca6e1ca4b 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
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -71,7 +72,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="comment">//    KILLER WHALE</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="string_literal injected">    Ishmael."</span><span class="semicolon injected">;</span>
     <span class="comment documentation">/// ```</span>
-    <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant associated declaration public">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="semicolon">;</span>
+    <span class="keyword">pub</span> <span class="keyword const">const</span> <span class="constant associated const declaration public static">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="semicolon">;</span>
 
     <span class="comment documentation">/// Constructs a new `Foo`.</span>
     <span class="comment documentation">///</span>
@@ -81,7 +82,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="comment documentation">///</span><span class="comment documentation"> #</span><span class="none injected"> </span><span class="attribute_bracket attribute injected">#</span><span class="attribute_bracket attribute injected">!</span><span class="attribute_bracket attribute injected">[</span><span class="builtin_attr attribute injected library">allow</span><span class="parenthesis attribute injected">(</span><span class="none attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute_bracket attribute injected">]</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="keyword injected">mut</span><span class="none injected"> </span><span class="variable declaration injected mutable">foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
     <span class="comment documentation">/// ```</span>
-    <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function associated declaration public static">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="brace">{</span>
+    <span class="keyword">pub</span> <span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function associated const declaration public static">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="brace">{</span>
         <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">bar</span><span class="colon">:</span> <span class="bool_literal">true</span> <span class="brace">}</span>
     <span class="brace">}</span>
 
@@ -109,25 +110,25 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="comment documentation">/// ```</span>
     <span class="comment documentation">///</span>
     <span class="comment documentation">/// ```rust,no_run</span>
-    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
+    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="method injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
     <span class="comment documentation">/// ```</span>
     <span class="comment documentation">///</span>
     <span class="comment documentation">/// ~~~rust,no_run</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="comment injected">// code block with tilde.</span>
-    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
+    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="method injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
     <span class="comment documentation">/// ~~~</span>
     <span class="comment documentation">///</span>
     <span class="comment documentation">/// ```</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="comment injected">// functions</span>
-    <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">foo</span><span class="angle injected">&lt;</span><span class="type_param declaration injected">T</span><span class="comma injected">,</span><span class="none injected"> </span><span class="keyword injected">const</span><span class="none injected"> </span><span class="const_param declaration injected">X</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">usize</span><span class="angle injected">&gt;</span><span class="parenthesis injected">(</span><span class="value_param declaration injected">arg</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">i32</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span>
-    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="none injected">    </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">x</span><span class="colon injected">:</span><span class="none injected"> </span><span class="type_param injected">T</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="const_param injected">X</span><span class="semicolon injected">;</span>
+    <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">foo</span><span class="angle injected">&lt;</span><span class="type_param declaration injected">T</span><span class="comma injected">,</span><span class="none injected"> </span><span class="keyword injected">const</span><span class="none injected"> </span><span class="const_param const declaration injected">X</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">usize</span><span class="angle injected">&gt;</span><span class="parenthesis injected">(</span><span class="value_param declaration injected">arg</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">i32</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span>
+    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="none injected">    </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">x</span><span class="colon injected">:</span><span class="none injected"> </span><span class="type_param injected">T</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="const_param const injected">X</span><span class="semicolon injected">;</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="brace injected">}</span>
     <span class="comment documentation">/// ```</span>
     <span class="comment documentation">///</span>
     <span class="comment documentation">/// ```sh</span>
     <span class="comment documentation">/// echo 1</span>
     <span class="comment documentation">/// ```</span>
-    <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function associated declaration public reference">foo</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="brace">{</span>
+    <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="method associated declaration public reference">foo</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="brace">{</span>
         <span class="bool_literal">true</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index 729e4791f55..129b287e52f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
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 066fcfb1dfe..7ba1194d675 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
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -63,25 +64,25 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="brace">}</span>
 
 <span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span>
-    <span class="keyword">fn</span> <span class="function associated declaration reference trait">bar</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span>
+    <span class="keyword">fn</span> <span class="method associated declaration reference trait">bar</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
 <span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span>
-    <span class="keyword">fn</span> <span class="function associated declaration reference trait">bar</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
+    <span class="keyword">fn</span> <span class="method associated declaration reference trait">bar</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
         <span class="self_keyword reference">self</span><span class="operator">.</span><span class="field">x</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
 
 <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span>
-    <span class="keyword">fn</span> <span class="function associated consuming declaration">baz</span><span class="parenthesis">(</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">Foo</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
-        <span class="value_param">f</span><span class="operator">.</span><span class="function associated consuming">baz</span><span class="parenthesis">(</span><span class="self_keyword consuming mutable">self</span><span class="parenthesis">)</span>
+    <span class="keyword">fn</span> <span class="method associated consuming declaration">baz</span><span class="parenthesis">(</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">Foo</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
+        <span class="value_param">f</span><span class="operator">.</span><span class="method consuming">baz</span><span class="parenthesis">(</span><span class="self_keyword consuming mutable">self</span><span class="parenthesis">)</span>
     <span class="brace">}</span>
 
-    <span class="keyword">fn</span> <span class="function associated declaration mutable reference">qux</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
+    <span class="keyword">fn</span> <span class="method associated declaration mutable reference">qux</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
         <span class="self_keyword mutable reference">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
     <span class="brace">}</span>
 
-    <span class="keyword">fn</span> <span class="function associated declaration reference">quop</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
+    <span class="keyword">fn</span> <span class="method associated declaration reference">quop</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
         <span class="self_keyword reference">self</span><span class="operator">.</span><span class="field">x</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
@@ -94,15 +95,15 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="brace">}</span>
 
 <span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="brace">{</span>
-    <span class="keyword">fn</span> <span class="function associated consuming declaration">baz</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">FooCopy</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
-        <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="parenthesis">)</span>
+    <span class="keyword">fn</span> <span class="method associated consuming declaration">baz</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">FooCopy</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
+        <span class="value_param">f</span><span class="operator">.</span><span class="method">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="parenthesis">)</span>
     <span class="brace">}</span>
 
-    <span class="keyword">fn</span> <span class="function associated declaration mutable reference">qux</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
+    <span class="keyword">fn</span> <span class="method associated declaration mutable reference">qux</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
         <span class="self_keyword mutable reference">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
     <span class="brace">}</span>
 
-    <span class="keyword">fn</span> <span class="function associated declaration reference">quop</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
+    <span class="keyword">fn</span> <span class="method associated declaration reference">quop</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
         <span class="self_keyword reference">self</span><span class="operator">.</span><span class="field">x</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
@@ -119,9 +120,9 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword control">loop</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="brace">{</span>
-    <span class="function">const_param</span><span class="operator">::</span><span class="angle">&lt;</span><span class="brace">{</span> <span class="const_param">FOO</span> <span class="brace">}</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="const_param">FOO</span>
+<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param const declaration">FOO</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="brace">{</span>
+    <span class="function">const_param</span><span class="operator">::</span><span class="angle">&lt;</span><span class="brace">{</span> <span class="const_param const">FOO</span> <span class="brace">}</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <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>
@@ -148,17 +149,17 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
     <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="unresolved_reference">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="unresolved_reference">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span>
-    <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated reference">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated mutable reference">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated consuming">baz</span><span class="parenthesis">(</span><span class="variable consuming">foo2</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="variable mutable">foo</span><span class="operator">.</span><span class="method reference">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="variable mutable">foo</span><span class="operator">.</span><span class="method mutable reference">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="variable mutable">foo</span><span class="operator">.</span><span class="method consuming">baz</span><span class="parenthesis">(</span><span class="variable consuming">foo2</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 
     <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="brace">{</span> <span class="field">x</span> <span class="brace">}</span><span class="semicolon">;</span>
-    <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated reference">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated mutable reference">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="variable mutable">copy</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="variable mutable">copy</span><span class="operator">.</span><span class="method reference">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="variable mutable">copy</span><span class="operator">.</span><span class="method mutable reference">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="variable mutable">copy</span><span class="operator">.</span><span class="method">baz</span><span class="parenthesis">(</span><span class="variable mutable">copy</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 
     <span class="keyword">let</span> <span class="variable callable declaration">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="semicolon">;</span>
-    <span class="keyword">let</span> <span class="variable callable declaration">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated consuming">baz</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable callable declaration">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="method associated consuming">baz</span><span class="semicolon">;</span>
 
     <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="comma">,</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="operator">.</span><span class="field">0</span><span class="semicolon">;</span>
@@ -178,7 +179,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span>
 
 <span class="keyword">impl</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="angle">&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">T</span><span class="angle">&gt;</span> <span class="brace">{</span>
-    <span class="keyword">fn</span> <span class="function associated consuming declaration">and</span><span class="angle">&lt;</span><span class="type_param declaration">U</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">other</span><span class="colon">:</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">U</span><span class="angle">&gt;</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="comma">,</span> <span class="type_param">U</span><span class="parenthesis">)</span><span class="angle">&gt;</span> <span class="brace">{</span>
+    <span class="keyword">fn</span> <span class="method associated consuming declaration">and</span><span class="angle">&lt;</span><span class="type_param declaration">U</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">other</span><span class="colon">:</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">U</span><span class="angle">&gt;</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="comma">,</span> <span class="type_param">U</span><span class="parenthesis">)</span><span class="angle">&gt;</span> <span class="brace">{</span>
         <span class="keyword control">match</span> <span class="value_param">other</span> <span class="brace">{</span>
             <span class="enum_variant">None</span> <span class="operator">=&gt;</span> <span class="unresolved_reference">unimplemented</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma">,</span>
             <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="comma">,</span>
@@ -200,12 +201,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="keyword">fn</span> <span class="function declaration">use_foo_items</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
     <span class="keyword">let</span> <span class="variable declaration">bob</span> <span class="operator">=</span> <span class="module crate_root library">foo</span><span class="operator">::</span><span class="struct library">Person</span> <span class="brace">{</span>
         <span class="field library">name</span><span class="colon">:</span> <span class="string_literal">"Bob"</span><span class="comma">,</span>
-        <span class="field library">age</span><span class="colon">:</span> <span class="module crate_root library">foo</span><span class="operator">::</span><span class="module library">consts</span><span class="operator">::</span><span class="constant library">NUMBER</span><span class="comma">,</span>
+        <span class="field library">age</span><span class="colon">:</span> <span class="module crate_root library">foo</span><span class="operator">::</span><span class="module library">consts</span><span class="operator">::</span><span class="constant const library">NUMBER</span><span class="comma">,</span>
     <span class="brace">}</span><span class="semicolon">;</span>
 
     <span class="keyword">let</span> <span class="variable declaration">control_flow</span> <span class="operator">=</span> <span class="module crate_root library">foo</span><span class="operator">::</span><span class="function library">identity</span><span class="parenthesis">(</span><span class="module crate_root library">foo</span><span class="operator">::</span><span class="enum library">ControlFlow</span><span class="operator">::</span><span class="enum_variant library">Continue</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 
-    <span class="keyword control">if</span> <span class="variable">control_flow</span><span class="operator">.</span><span class="function associated consuming library">should_die</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
+    <span class="keyword control">if</span> <span class="variable">control_flow</span><span class="operator">.</span><span class="method consuming library">should_die</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
         <span class="module crate_root library">foo</span><span class="operator">::</span><span class="unresolved_reference">die</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
@@ -213,23 +214,23 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="keyword">pub</span> <span class="keyword">enum</span> <span class="enum declaration public">Bool</span> <span class="brace">{</span> <span class="enum_variant declaration public">True</span><span class="comma">,</span> <span class="enum_variant declaration public">False</span> <span class="brace">}</span>
 
 <span class="keyword">impl</span> <span class="enum public">Bool</span> <span class="brace">{</span>
-    <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function associated consuming declaration public">to_primitive</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="brace">{</span>
+    <span class="keyword">pub</span> <span class="keyword const">const</span> <span class="keyword">fn</span> <span class="method associated const consuming declaration public">to_primitive</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="brace">{</span>
         <span class="bool_literal">true</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
-<span class="keyword">const</span> <span class="constant declaration">USAGE_OF_BOOL</span><span class="colon">:</span><span class="builtin_type">bool</span> <span class="operator">=</span> <span class="enum public">Bool</span><span class="operator">::</span><span class="enum_variant public">True</span><span class="operator">.</span><span class="function associated consuming public">to_primitive</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+<span class="keyword const">const</span> <span class="constant const declaration">USAGE_OF_BOOL</span><span class="colon">:</span><span class="builtin_type">bool</span> <span class="operator">=</span> <span class="enum public">Bool</span><span class="operator">::</span><span class="enum_variant public">True</span><span class="operator">.</span><span class="method consuming public">to_primitive</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 
 <span class="keyword">trait</span> <span class="trait declaration">Baz</span> <span class="brace">{</span>
-    <span class="keyword">type</span> <span class="type_alias associated declaration trait">Qux</span><span class="semicolon">;</span>
+    <span class="keyword">type</span> <span class="type_alias associated declaration static trait">Qux</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
 <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="value_param declaration">t</span><span class="colon">:</span> <span class="type_param">T</span><span class="parenthesis">)</span>
 <span class="keyword">where</span>
     <span class="type_param">T</span><span class="colon">:</span> <span class="trait">Baz</span><span class="comma">,</span>
-    <span class="angle">&lt;</span><span class="type_param">T</span> <span class="keyword">as</span> <span class="trait">Baz</span><span class="angle">&gt;</span><span class="operator">::</span><span class="type_alias associated trait">Qux</span><span class="colon">:</span> <span class="trait">Bar</span> <span class="brace">{</span><span class="brace">}</span>
+    <span class="angle">&lt;</span><span class="type_param">T</span> <span class="keyword">as</span> <span class="trait">Baz</span><span class="angle">&gt;</span><span class="operator">::</span><span class="type_alias associated static trait">Qux</span><span class="colon">:</span> <span class="trait">Bar</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">fn</span> <span class="function declaration">gp_shadows_trait</span><span class="angle">&lt;</span><span class="type_param declaration">Baz</span><span class="colon">:</span> <span class="trait">Bar</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
-    <span class="type_param">Baz</span><span class="operator">::</span><span class="function associated reference trait">bar</span><span class="semicolon">;</span>
+    <span class="type_param">Baz</span><span class="operator">::</span><span class="method associated reference trait">bar</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
 </code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 58a147dd80a..6c3fbcfcf41 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
index 22ae5c82a4b..7064a877070 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
index af779996593..8428b815800 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
index 32ac6a94d86..573b3d4bd52 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
index ef8a48ca1c1..947d1bf1e35 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
index a2ded15fd1b..0fe2b6f274d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
index d123ee04976..c60b6ab27bb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
index 4429e5d933a..5d51b149789 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index b6458fa7ca0..7a07d17b271 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -171,9 +172,9 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         <span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">i</span><span class="comma macro">,</span>
     <span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
-    <span class="keyword">const</span> <span class="constant declaration">CONSTANT</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="colon">:</span>
+    <span class="keyword const">const</span> <span class="constant const declaration">CONSTANT</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="colon">:</span>
     <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">m</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro default_library library macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable reference">backslash</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="constant">CONSTANT</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable mutable">m</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="macro default_library library macro">format_args</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="macro macro">toho</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable reference">backslash</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="constant const">CONSTANT</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable mutable">m</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="macro default_library library macro">format_args</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="macro macro">toho</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">reuse_twice</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable reference">backslash</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 49b588baa58..15d6be6334c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -40,6 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .keyword            { color: #F0DFAF; font-weight: bold; }
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
 
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
@@ -65,7 +66,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 <span class="keyword">struct</span> <span class="struct declaration">Struct</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="builtin_type">i32</span> <span class="brace">}</span>
 <span class="keyword">impl</span> <span class="struct">Struct</span> <span class="brace">{</span>
-    <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function associated declaration reference unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+    <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="method associated declaration reference unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</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 library">repr</span><span class="parenthesis attribute">(</span><span class="none attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
@@ -80,11 +81,11 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="keyword">fn</span> <span class="function declaration">unsafe_trait_bound</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="colon">:</span> <span class="trait">UnsafeTrait</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="type_param">T</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span>
-    <span class="keyword">fn</span> <span class="function associated declaration reference trait">calls_autoref</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="keyword">fn</span> <span class="method associated declaration reference trait">calls_autoref</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
 <span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span>
-    <span class="keyword">fn</span> <span class="function associated declaration reference trait">calls_autoref</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+    <span class="keyword">fn</span> <span class="method associated declaration reference trait">calls_autoref</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
@@ -106,7 +107,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
             <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span> <span class="operator">=&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
             <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">a</span> <span class="brace">}</span> <span class="operator">=&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
         <span class="brace">}</span>
-        <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="operator">.</span><span class="function associated reference unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+        <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="operator">.</span><span class="method reference unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 
         <span class="comment">// unsafe deref</span>
         <span class="operator unsafe">*</span><span class="variable">x</span><span class="semicolon">;</span>
@@ -123,6 +124,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration reference">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
 
         <span class="comment">// unsafe auto ref of packed field</span>
-        <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated reference trait unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+        <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="method reference trait unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="brace">}</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
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 6fed7d783e8..c2990fd76ea 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
@@ -22,11 +22,11 @@ fn attributes() {
     check_highlighting(
         r#"
 //- proc_macros: identity
-//- minicore: derive, copy
+//- minicore: derive, copy, default
 #[allow(dead_code)]
 #[rustfmt::skip]
 #[proc_macros::identity]
-#[derive(Copy)]
+#[derive(Default)]
 /// This is a doc comment
 // This is a normal comment
 /// This is a doc comment
@@ -36,7 +36,10 @@ fn attributes() {
 // This is another normal comment
 #[derive(Copy, Unresolved)]
 // The reason for these being here is to test AttrIds
-struct Foo;
+enum Foo {
+    #[default]
+    Bar
+}
 "#,
         expect_file!["./test_data/highlight_attributes.html"],
         false,
@@ -630,6 +633,52 @@ fn main() {
 }
 
 #[test]
+fn test_const_highlighting() {
+    check_highlighting(
+        r#"
+macro_rules! id {
+    ($($tt:tt)*) => {
+        $($tt)*
+    };
+}
+const CONST_ITEM: *const () = &raw const ();
+const fn const_fn<const CONST_PARAM: ()>(const {}: const fn()) where (): const ConstTrait {
+    CONST_ITEM;
+    CONST_PARAM;
+    const {
+        const || {}
+    }
+    id!(
+        CONST_ITEM;
+        CONST_PARAM;
+        const {
+            const || {}
+        };
+        &raw const ();
+        const
+    );
+}
+trait ConstTrait {
+    const ASSOC_CONST: () = ();
+    const fn assoc_const_fn() {}
+}
+impl const ConstTrait for () {
+    const ASSOC_CONST: () = ();
+    const fn assoc_const_fn() {}
+}
+
+macro_rules! unsafe_deref {
+    () => {
+        *(&() as *const ())
+    };
+}
+"#,
+        expect_file!["./test_data/highlight_const.html"],
+        false,
+    );
+}
+
+#[test]
 fn test_highlight_doc_comment() {
     check_highlighting(
         r#"
@@ -1173,8 +1222,27 @@ fn benchmark_syntax_highlighting_parser() {
             .highlight(HL_CONFIG, file_id)
             .unwrap()
             .iter()
-            .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function))
+            .filter(|it| {
+                matches!(it.highlight.tag, HlTag::Symbol(SymbolKind::Function | SymbolKind::Method))
+            })
             .count()
     };
     assert_eq!(hash, 1169);
 }
+
+#[test]
+fn highlight_trait_with_lifetimes_regression_16958() {
+    let (analysis, file_id) = fixture::file(
+        r#"
+pub trait Deserialize<'de> {
+    fn deserialize();
+}
+
+fn f<'de, T: Deserialize<'de>>() {
+    T::deserialize();
+}
+"#
+        .trim(),
+    );
+    let _ = analysis.highlight(HL_CONFIG, file_id).unwrap();
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
index ca471399703..99e24308607 100644
--- a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
@@ -7,7 +7,7 @@ use ide_db::{
 };
 use syntax::TextRange;
 
-use crate::{navigation_target::ToNav, runnables::runnable_fn, Runnable, TryToNav};
+use crate::{runnables::runnable_fn, NavigationTarget, Runnable, TryToNav};
 
 #[derive(Debug)]
 pub enum TestItemKind {
@@ -56,7 +56,12 @@ fn find_crate_by_id(crate_graph: &CrateGraph, crate_id: &str) -> Option<CrateId>
     })
 }
 
-fn discover_tests_in_module(db: &RootDatabase, module: Module, prefix_id: String) -> Vec<TestItem> {
+fn discover_tests_in_module(
+    db: &RootDatabase,
+    module: Module,
+    prefix_id: String,
+    only_in_this_file: bool,
+) -> Vec<TestItem> {
     let sema = Semantics::new(db);
 
     let mut r = vec![];
@@ -64,9 +69,9 @@ fn discover_tests_in_module(db: &RootDatabase, module: Module, prefix_id: String
         let module_name =
             c.name(db).as_ref().and_then(|n| n.as_str()).unwrap_or("[mod without name]").to_owned();
         let module_id = format!("{prefix_id}::{module_name}");
-        let module_children = discover_tests_in_module(db, c, module_id.clone());
+        let module_children = discover_tests_in_module(db, c, module_id.clone(), only_in_this_file);
         if !module_children.is_empty() {
-            let nav = c.to_nav(db).call_site;
+            let nav = NavigationTarget::from_module_to_decl(sema.db, c).call_site;
             r.push(TestItem {
                 id: module_id,
                 kind: TestItemKind::Module,
@@ -76,7 +81,9 @@ fn discover_tests_in_module(db: &RootDatabase, module: Module, prefix_id: String
                 text_range: Some(nav.focus_or_full_range()),
                 runnable: None,
             });
-            r.extend(module_children);
+            if !only_in_this_file || c.is_inline(db) {
+                r.extend(module_children);
+            }
         }
     }
     for def in module.declarations(db) {
@@ -112,6 +119,55 @@ pub(crate) fn discover_tests_in_crate_by_test_id(
     discover_tests_in_crate(db, crate_id)
 }
 
+pub(crate) fn discover_tests_in_file(db: &RootDatabase, file_id: FileId) -> Vec<TestItem> {
+    let sema = Semantics::new(db);
+
+    let Some(module) = sema.file_to_module_def(file_id) else { return vec![] };
+    let Some((mut tests, id)) = find_module_id_and_test_parents(&sema, module) else {
+        return vec![];
+    };
+    tests.extend(discover_tests_in_module(db, module, id, true));
+    tests
+}
+
+fn find_module_id_and_test_parents(
+    sema: &Semantics<'_, RootDatabase>,
+    module: Module,
+) -> Option<(Vec<TestItem>, String)> {
+    let Some(parent) = module.parent(sema.db) else {
+        let name = module.krate().display_name(sema.db)?.to_string();
+        return Some((
+            vec![TestItem {
+                id: name.clone(),
+                kind: TestItemKind::Crate(module.krate().into()),
+                label: name.clone(),
+                parent: None,
+                file: None,
+                text_range: None,
+                runnable: None,
+            }],
+            name,
+        ));
+    };
+    let (mut r, mut id) = find_module_id_and_test_parents(sema, parent)?;
+    let parent = Some(id.clone());
+    id += "::";
+    let module_name = &module.name(sema.db);
+    let module_name = module_name.as_ref().and_then(|n| n.as_str()).unwrap_or("[mod without name]");
+    id += module_name;
+    let nav = NavigationTarget::from_module_to_decl(sema.db, module).call_site;
+    r.push(TestItem {
+        id: id.clone(),
+        kind: TestItemKind::Module,
+        label: module_name.to_owned(),
+        parent,
+        file: Some(nav.file_id),
+        text_range: Some(nav.focus_or_full_range()),
+        runnable: None,
+    });
+    Some((r, id))
+}
+
 pub(crate) fn discover_tests_in_crate(db: &RootDatabase, crate_id: CrateId) -> Vec<TestItem> {
     let crate_graph = db.crate_graph();
     if !crate_graph[crate_id].origin.is_local() {
@@ -133,6 +189,6 @@ pub(crate) fn discover_tests_in_crate(db: &RootDatabase, crate_id: CrateId) -> V
         text_range: None,
         runnable: None,
     }];
-    r.extend(discover_tests_in_module(db, module, crate_test_id));
+    r.extend(discover_tests_in_module(db, module, crate_test_id, false));
     r
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index e87fc89fea2..d3eee0e02e4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -175,9 +175,21 @@ fn on_opening_bracket_typed(
             }
         }
 
-        // If it's a statement in a block, we don't know how many statements should be included
-        if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) {
-            return None;
+        if let Some(parent) = expr.syntax().parent().and_then(ast::Expr::cast) {
+            let mut node = expr.syntax().clone();
+            let all_prev_sib_attr = loop {
+                match node.prev_sibling() {
+                    Some(sib) if sib.kind().is_trivia() || sib.kind() == SyntaxKind::ATTR => {
+                        node = sib
+                    }
+                    Some(_) => break false,
+                    None => break true,
+                };
+            };
+
+            if all_prev_sib_attr {
+                expr = parent;
+            }
         }
 
         // Insert the closing bracket right after the expression.
@@ -827,6 +839,21 @@ fn f() {
 }
             "#,
         );
+        type_char(
+            '{',
+            r#"
+fn main() {
+    #[allow(unreachable_code)]
+    $0g();
+}
+            "#,
+            r#"
+fn main() {
+    #[allow(unreachable_code)]
+    {g()};
+}
+            "#,
+        );
     }
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/load-cargo/Cargo.toml b/src/tools/rust-analyzer/crates/load-cargo/Cargo.toml
index 05412e176b6..48e84a7b25e 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/load-cargo/Cargo.toml
@@ -20,6 +20,7 @@ tracing.workspace = true
 
 hir-expand.workspace = true
 ide-db.workspace = true
+paths.workspace = true
 proc-macro-api.workspace = true
 project-model.workspace = true
 span.workspace = true
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 fe680e47fef..79d6fe36b56 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -38,7 +38,7 @@ pub fn load_workspace_at(
     load_config: &LoadCargoConfig,
     progress: &dyn Fn(String),
 ) -> anyhow::Result<(RootDatabase, vfs::Vfs, Option<ProcMacroServer>)> {
-    let root = AbsPathBuf::assert(std::env::current_dir()?.join(root));
+    let root = AbsPathBuf::assert_utf8(std::env::current_dir()?.join(root));
     let root = ProjectManifest::discover_single(&root)?;
     let mut workspace = ProjectWorkspace::load(root, cargo_config, progress)?;
 
@@ -387,7 +387,7 @@ fn expander_to_proc_macro(
     let name = From::from(expander.name());
     let kind = match expander.kind() {
         proc_macro_api::ProcMacroKind::CustomDerive => ProcMacroKind::CustomDerive,
-        proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike,
+        proc_macro_api::ProcMacroKind::Bang => ProcMacroKind::Bang,
         proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr,
     };
     let disabled = ignored_macros.iter().any(|replace| **replace == name);
diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
index ac7f0711784..4d5531ae307 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
@@ -23,7 +23,11 @@ fn benchmark_parse_macro_rules() {
         let _pt = bench("mbe parse macro rules");
         rules
             .values()
-            .map(|it| DeclarativeMacro::parse_macro_rules(it, true, true).rules.len())
+            .map(|it| {
+                DeclarativeMacro::parse_macro_rules(it, |_| span::Edition::CURRENT, true)
+                    .rules
+                    .len()
+            })
             .sum()
     };
     assert_eq!(hash, 1144);
@@ -51,10 +55,12 @@ fn benchmark_expand_macro_rules() {
     assert_eq!(hash, 69413);
 }
 
-fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro<Span>> {
+fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro> {
     macro_rules_fixtures_tt()
         .into_iter()
-        .map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt, true, true)))
+        .map(|(id, tt)| {
+            (id, DeclarativeMacro::parse_macro_rules(&tt, |_| span::Edition::CURRENT, true))
+        })
         .collect()
 }
 
@@ -80,7 +86,7 @@ fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::Subtree<Span>> {
 
 /// Generate random invocation fixtures from rules
 fn invocation_fixtures(
-    rules: &FxHashMap<String, DeclarativeMacro<Span>>,
+    rules: &FxHashMap<String, DeclarativeMacro>,
 ) -> Vec<(String, tt::Subtree<Span>)> {
     let mut seed = 123456789;
     let mut res = Vec::new();
@@ -128,11 +134,7 @@ fn invocation_fixtures(
     }
     return res;
 
-    fn collect_from_op(
-        op: &Op<Span>,
-        token_trees: &mut Vec<tt::TokenTree<Span>>,
-        seed: &mut usize,
-    ) {
+    fn collect_from_op(op: &Op, token_trees: &mut Vec<tt::TokenTree<Span>>, seed: &mut usize) {
         return match op {
             Op::Var { kind, .. } => match kind.as_ref() {
                 Some(MetaVarKind::Ident) => token_trees.push(make_ident("foo")),
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander.rs b/src/tools/rust-analyzer/crates/mbe/src/expander.rs
index 9366048fd95..2f2c0aa6ff5 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander.rs
@@ -6,22 +6,21 @@ mod matcher;
 mod transcriber;
 
 use rustc_hash::FxHashMap;
+use span::Span;
 use syntax::SmolStr;
-use tt::Span;
 
 use crate::{parser::MetaVarKind, ExpandError, ExpandResult};
 
-pub(crate) fn expand_rules<S: Span>(
-    rules: &[crate::Rule<S>],
-    input: &tt::Subtree<S>,
-    marker: impl Fn(&mut S) + Copy,
-    is_2021: bool,
+pub(crate) fn expand_rules(
+    rules: &[crate::Rule],
+    input: &tt::Subtree<Span>,
+    marker: impl Fn(&mut Span) + Copy,
     new_meta_vars: bool,
-    call_site: S,
-) -> ExpandResult<tt::Subtree<S>> {
-    let mut match_: Option<(matcher::Match<S>, &crate::Rule<S>)> = None;
+    call_site: Span,
+) -> ExpandResult<tt::Subtree<Span>> {
+    let mut match_: Option<(matcher::Match, &crate::Rule)> = None;
     for rule in rules {
-        let new_match = matcher::match_(&rule.lhs, input, is_2021);
+        let new_match = matcher::match_(&rule.lhs, input);
 
         if new_match.err.is_none() {
             // If we find a rule that applies without errors, we're done.
@@ -110,30 +109,24 @@ pub(crate) fn expand_rules<S: Span>(
 /// In other words, `Bindings` is a *multi* mapping from `SmolStr` to
 /// `tt::TokenTree`, where the index to select a particular `TokenTree` among
 /// many is not a plain `usize`, but a `&[usize]`.
-#[derive(Debug, Clone, PartialEq, Eq)]
-struct Bindings<S> {
-    inner: FxHashMap<SmolStr, Binding<S>>,
-}
-
-impl<S> Default for Bindings<S> {
-    fn default() -> Self {
-        Self { inner: Default::default() }
-    }
+#[derive(Debug, Default, Clone, PartialEq, Eq)]
+struct Bindings {
+    inner: FxHashMap<SmolStr, Binding>,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
-enum Binding<S> {
-    Fragment(Fragment<S>),
-    Nested(Vec<Binding<S>>),
+enum Binding {
+    Fragment(Fragment),
+    Nested(Vec<Binding>),
     Empty,
     Missing(MetaVarKind),
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
-enum Fragment<S> {
+enum Fragment {
     Empty,
     /// token fragments are just copy-pasted into the output
-    Tokens(tt::TokenTree<S>),
+    Tokens(tt::TokenTree<Span>),
     /// Expr ast fragments are surrounded with `()` on insertion to preserve
     /// precedence. Note that this impl is different from the one currently in
     /// `rustc` -- `rustc` doesn't translate fragments into token trees at all.
@@ -141,7 +134,7 @@ enum Fragment<S> {
     /// At one point in time, we tried to use "fake" delimiters here à la
     /// proc-macro delimiter=none. As we later discovered, "none" delimiters are
     /// tricky to handle in the parser, and rustc doesn't handle those either.
-    Expr(tt::Subtree<S>),
+    Expr(tt::Subtree<Span>),
     /// There are roughly two types of paths: paths in expression context, where a
     /// separator `::` between an identifier and its following generic argument list
     /// is mandatory, and paths in type context, where `::` can be omitted.
@@ -151,5 +144,5 @@ enum Fragment<S> {
     /// and is trasncribed as an expression-context path, verbatim transcription
     /// would cause a syntax error. We need to fix it up just before transcribing;
     /// see `transcriber::fix_up_and_push_path_tt()`.
-    Path(tt::Subtree<S>),
+    Path(tt::Subtree<Span>),
 }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
index eea92cfba4c..3170834d54f 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
@@ -62,8 +62,9 @@
 use std::rc::Rc;
 
 use smallvec::{smallvec, SmallVec};
+use span::Span;
 use syntax::SmolStr;
-use tt::{DelimSpan, Span};
+use tt::DelimSpan;
 
 use crate::{
     expander::{Binding, Bindings, ExpandResult, Fragment},
@@ -72,7 +73,7 @@ use crate::{
     ExpandError, MetaTemplate, ValueResult,
 };
 
-impl<S: Span> Bindings<S> {
+impl Bindings {
     fn push_optional(&mut self, name: &SmolStr) {
         self.inner.insert(name.clone(), Binding::Fragment(Fragment::Empty));
     }
@@ -81,14 +82,14 @@ impl<S: Span> Bindings<S> {
         self.inner.insert(name.clone(), Binding::Empty);
     }
 
-    fn bindings(&self) -> impl Iterator<Item = &Binding<S>> {
+    fn bindings(&self) -> impl Iterator<Item = &Binding> {
         self.inner.values()
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub(super) struct Match<S> {
-    pub(super) bindings: Bindings<S>,
+#[derive(Clone, Default, Debug, PartialEq, Eq)]
+pub(super) struct Match {
+    pub(super) bindings: Bindings,
     /// We currently just keep the first error and count the rest to compare matches.
     pub(super) err: Option<ExpandError>,
     pub(super) err_count: usize,
@@ -98,19 +99,7 @@ pub(super) struct Match<S> {
     pub(super) bound_count: usize,
 }
 
-impl<S> Default for Match<S> {
-    fn default() -> Self {
-        Self {
-            bindings: Default::default(),
-            err: Default::default(),
-            err_count: Default::default(),
-            unmatched_tts: Default::default(),
-            bound_count: Default::default(),
-        }
-    }
-}
-
-impl<S> Match<S> {
+impl Match {
     fn add_err(&mut self, err: ExpandError) {
         let prev_err = self.err.take();
         self.err = prev_err.or(Some(err));
@@ -119,16 +108,12 @@ impl<S> Match<S> {
 }
 
 /// Matching errors are added to the `Match`.
-pub(super) fn match_<S: Span>(
-    pattern: &MetaTemplate<S>,
-    input: &tt::Subtree<S>,
-    is_2021: bool,
-) -> Match<S> {
-    let mut res = match_loop(pattern, input, is_2021);
+pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree<Span>) -> Match {
+    let mut res = match_loop(pattern, input);
     res.bound_count = count(res.bindings.bindings());
     return res;
 
-    fn count<'a, S: 'a>(bindings: impl Iterator<Item = &'a Binding<S>>) -> usize {
+    fn count<'a>(bindings: impl Iterator<Item = &'a Binding>) -> usize {
         bindings
             .map(|it| match it {
                 Binding::Fragment(_) => 1,
@@ -141,10 +126,10 @@ pub(super) fn match_<S: Span>(
 }
 
 #[derive(Debug, Clone)]
-enum BindingKind<S> {
+enum BindingKind {
     Empty(SmolStr),
     Optional(SmolStr),
-    Fragment(SmolStr, Fragment<S>),
+    Fragment(SmolStr, Fragment),
     Missing(SmolStr, MetaVarKind),
     Nested(usize, usize),
 }
@@ -158,18 +143,13 @@ enum LinkNode<T> {
     Parent { idx: usize, len: usize },
 }
 
-struct BindingsBuilder<S> {
-    nodes: Vec<Vec<LinkNode<Rc<BindingKind<S>>>>>,
+#[derive(Default)]
+struct BindingsBuilder {
+    nodes: Vec<Vec<LinkNode<Rc<BindingKind>>>>,
     nested: Vec<Vec<LinkNode<usize>>>,
 }
 
-impl<S> Default for BindingsBuilder<S> {
-    fn default() -> Self {
-        Self { nodes: Default::default(), nested: Default::default() }
-    }
-}
-
-impl<S: Span> BindingsBuilder<S> {
+impl BindingsBuilder {
     fn alloc(&mut self) -> BindingsIdx {
         let idx = self.nodes.len();
         self.nodes.push(Vec::new());
@@ -206,7 +186,7 @@ impl<S: Span> BindingsBuilder<S> {
         self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Optional(var.clone()))));
     }
 
-    fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &SmolStr, fragment: Fragment<S>) {
+    fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &SmolStr, fragment: Fragment) {
         self.nodes[idx.0]
             .push(LinkNode::Node(Rc::new(BindingKind::Fragment(var.clone(), fragment))));
     }
@@ -227,11 +207,11 @@ impl<S: Span> BindingsBuilder<S> {
         idx.0 = new_idx;
     }
 
-    fn build(self, idx: &BindingsIdx) -> Bindings<S> {
+    fn build(self, idx: &BindingsIdx) -> Bindings {
         self.build_inner(&self.nodes[idx.0])
     }
 
-    fn build_inner(&self, link_nodes: &[LinkNode<Rc<BindingKind<S>>>]) -> Bindings<S> {
+    fn build_inner(&self, link_nodes: &[LinkNode<Rc<BindingKind>>]) -> Bindings {
         let mut bindings = Bindings::default();
         let mut nodes = Vec::new();
         self.collect_nodes(link_nodes, &mut nodes);
@@ -281,7 +261,7 @@ impl<S: Span> BindingsBuilder<S> {
         &'a self,
         id: usize,
         len: usize,
-        nested_refs: &mut Vec<&'a [LinkNode<Rc<BindingKind<S>>>]>,
+        nested_refs: &mut Vec<&'a [LinkNode<Rc<BindingKind>>]>,
     ) {
         self.nested[id].iter().take(len).for_each(|it| match it {
             LinkNode::Node(id) => nested_refs.push(&self.nodes[*id]),
@@ -289,7 +269,7 @@ impl<S: Span> BindingsBuilder<S> {
         });
     }
 
-    fn collect_nested(&self, idx: usize, nested_idx: usize, nested: &mut Vec<Bindings<S>>) {
+    fn collect_nested(&self, idx: usize, nested_idx: usize, nested: &mut Vec<Bindings>) {
         let last = &self.nodes[idx];
         let mut nested_refs: Vec<&[_]> = Vec::new();
         self.nested[nested_idx].iter().for_each(|it| match *it {
@@ -300,7 +280,7 @@ impl<S: Span> BindingsBuilder<S> {
         nested.extend(nested_refs.into_iter().map(|iter| self.build_inner(iter)));
     }
 
-    fn collect_nodes_ref<'a>(&'a self, id: usize, len: usize, nodes: &mut Vec<&'a BindingKind<S>>) {
+    fn collect_nodes_ref<'a>(&'a self, id: usize, len: usize, nodes: &mut Vec<&'a BindingKind>) {
         self.nodes[id].iter().take(len).for_each(|it| match it {
             LinkNode::Node(it) => nodes.push(it),
             LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes),
@@ -309,8 +289,8 @@ impl<S: Span> BindingsBuilder<S> {
 
     fn collect_nodes<'a>(
         &'a self,
-        link_nodes: &'a [LinkNode<Rc<BindingKind<S>>>],
-        nodes: &mut Vec<&'a BindingKind<S>>,
+        link_nodes: &'a [LinkNode<Rc<BindingKind>>],
+        nodes: &mut Vec<&'a BindingKind>,
     ) {
         link_nodes.iter().for_each(|it| match it {
             LinkNode::Node(it) => nodes.push(it),
@@ -320,22 +300,22 @@ impl<S: Span> BindingsBuilder<S> {
 }
 
 #[derive(Debug, Clone)]
-struct MatchState<'t, S> {
+struct MatchState<'t> {
     /// The position of the "dot" in this matcher
-    dot: OpDelimitedIter<'t, S>,
+    dot: OpDelimitedIter<'t>,
 
     /// Token subtree stack
     /// When matching against matchers with nested delimited submatchers (e.g., `pat ( pat ( .. )
     /// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does
     /// that where the bottom of the stack is the outermost matcher.
-    stack: SmallVec<[OpDelimitedIter<'t, S>; 4]>,
+    stack: SmallVec<[OpDelimitedIter<'t>; 4]>,
 
     /// The "parent" matcher position if we are in a repetition. That is, the matcher position just
     /// before we enter the repetition.
-    up: Option<Box<MatchState<'t, S>>>,
+    up: Option<Box<MatchState<'t>>>,
 
     /// The separator if we are in a repetition.
-    sep: Option<Separator<S>>,
+    sep: Option<Separator>,
 
     /// The KleeneOp of this sequence if we are in a repetition.
     sep_kind: Option<RepeatKind>,
@@ -347,7 +327,7 @@ struct MatchState<'t, S> {
     bindings: BindingsIdx,
 
     /// Cached result of meta variable parsing
-    meta_result: Option<(TtIter<'t, S>, ExpandResult<Option<Fragment<S>>>)>,
+    meta_result: Option<(TtIter<'t, Span>, ExpandResult<Option<Fragment>>)>,
 
     /// Is error occurred in this state, will `poised` to "parent"
     is_error: bool,
@@ -372,18 +352,17 @@ struct MatchState<'t, S> {
 /// - `bb_items`: the set of items that are waiting for the black-box parser.
 /// - `error_items`: the set of items in errors, used for error-resilient parsing
 #[inline]
-fn match_loop_inner<'t, S: Span>(
-    src: TtIter<'t, S>,
-    stack: &[TtIter<'t, S>],
-    res: &mut Match<S>,
-    bindings_builder: &mut BindingsBuilder<S>,
-    cur_items: &mut SmallVec<[MatchState<'t, S>; 1]>,
-    bb_items: &mut SmallVec<[MatchState<'t, S>; 1]>,
-    next_items: &mut Vec<MatchState<'t, S>>,
-    eof_items: &mut SmallVec<[MatchState<'t, S>; 1]>,
-    error_items: &mut SmallVec<[MatchState<'t, S>; 1]>,
-    is_2021: bool,
-    delim_span: tt::DelimSpan<S>,
+fn match_loop_inner<'t>(
+    src: TtIter<'t, Span>,
+    stack: &[TtIter<'t, Span>],
+    res: &mut Match,
+    bindings_builder: &mut BindingsBuilder,
+    cur_items: &mut SmallVec<[MatchState<'t>; 1]>,
+    bb_items: &mut SmallVec<[MatchState<'t>; 1]>,
+    next_items: &mut Vec<MatchState<'t>>,
+    eof_items: &mut SmallVec<[MatchState<'t>; 1]>,
+    error_items: &mut SmallVec<[MatchState<'t>; 1]>,
+    delim_span: tt::DelimSpan<Span>,
 ) {
     macro_rules! try_push {
         ($items: expr, $it:expr) => {
@@ -494,7 +473,7 @@ fn match_loop_inner<'t, S: Span>(
             OpDelimited::Op(Op::Var { kind, name, .. }) => {
                 if let &Some(kind) = kind {
                     let mut fork = src.clone();
-                    let match_res = match_meta_var(kind, &mut fork, is_2021, delim_span);
+                    let match_res = match_meta_var(kind, &mut fork, delim_span);
                     match match_res.err {
                         None => {
                             // Some meta variables are optional (e.g. vis)
@@ -607,10 +586,10 @@ fn match_loop_inner<'t, S: Span>(
     }
 }
 
-fn match_loop<S: Span>(pattern: &MetaTemplate<S>, src: &tt::Subtree<S>, is_2021: bool) -> Match<S> {
+fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>) -> Match {
     let span = src.delimiter.delim_span();
     let mut src = TtIter::new(src);
-    let mut stack: SmallVec<[TtIter<'_, S>; 1]> = SmallVec::new();
+    let mut stack: SmallVec<[TtIter<'_, Span>; 1]> = SmallVec::new();
     let mut res = Match::default();
     let mut error_recover_item = None;
 
@@ -647,7 +626,6 @@ fn match_loop<S: Span>(pattern: &MetaTemplate<S>, src: &tt::Subtree<S>, is_2021:
             &mut next_items,
             &mut eof_items,
             &mut error_items,
-            is_2021,
             span,
         );
         stdx::always!(cur_items.is_empty());
@@ -758,12 +736,11 @@ fn match_loop<S: Span>(pattern: &MetaTemplate<S>, src: &tt::Subtree<S>, is_2021:
     }
 }
 
-fn match_meta_var<S: Span>(
+fn match_meta_var(
     kind: MetaVarKind,
-    input: &mut TtIter<'_, S>,
-    is_2021: bool,
-    delim_span: DelimSpan<S>,
-) -> ExpandResult<Option<Fragment<S>>> {
+    input: &mut TtIter<'_, Span>,
+    delim_span: DelimSpan<Span>,
+) -> ExpandResult<Option<Fragment>> {
     let fragment = match kind {
         MetaVarKind::Path => {
             return input.expect_fragment(parser::PrefixEntryPoint::Path).map(|it| {
@@ -771,8 +748,7 @@ fn match_meta_var<S: Span>(
             });
         }
         MetaVarKind::Ty => parser::PrefixEntryPoint::Ty,
-        MetaVarKind::Pat if is_2021 => parser::PrefixEntryPoint::PatTop,
-        MetaVarKind::Pat => parser::PrefixEntryPoint::Pat,
+        MetaVarKind::Pat => parser::PrefixEntryPoint::PatTop,
         MetaVarKind::PatParam => parser::PrefixEntryPoint::Pat,
         MetaVarKind::Stmt => parser::PrefixEntryPoint::Stmt,
         MetaVarKind::Block => parser::PrefixEntryPoint::Block,
@@ -846,7 +822,7 @@ fn match_meta_var<S: Span>(
     input.expect_fragment(fragment).map(|it| it.map(Fragment::Tokens))
 }
 
-fn collect_vars<S: Span>(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate<S>) {
+fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate) {
     for op in pattern.iter() {
         match op {
             Op::Var { name, .. } => collector_fun(name.clone()),
@@ -859,11 +835,11 @@ fn collect_vars<S: Span>(collector_fun: &mut impl FnMut(SmolStr), pattern: &Meta
         }
     }
 }
-impl<S: Span> MetaTemplate<S> {
-    fn iter_delimited_with(&self, delimiter: tt::Delimiter<S>) -> OpDelimitedIter<'_, S> {
+impl MetaTemplate {
+    fn iter_delimited_with(&self, delimiter: tt::Delimiter<Span>) -> OpDelimitedIter<'_> {
         OpDelimitedIter { inner: &self.0, idx: 0, delimited: delimiter }
     }
-    fn iter_delimited(&self, span: tt::DelimSpan<S>) -> OpDelimitedIter<'_, S> {
+    fn iter_delimited(&self, span: tt::DelimSpan<Span>) -> OpDelimitedIter<'_> {
         OpDelimitedIter {
             inner: &self.0,
             idx: 0,
@@ -873,27 +849,27 @@ impl<S: Span> MetaTemplate<S> {
 }
 
 #[derive(Debug, Clone, Copy)]
-enum OpDelimited<'a, S> {
-    Op(&'a Op<S>),
+enum OpDelimited<'a> {
+    Op(&'a Op),
     Open,
     Close,
 }
 
 #[derive(Debug, Clone, Copy)]
-struct OpDelimitedIter<'a, S> {
-    inner: &'a [Op<S>],
-    delimited: tt::Delimiter<S>,
+struct OpDelimitedIter<'a> {
+    inner: &'a [Op],
+    delimited: tt::Delimiter<Span>,
     idx: usize,
 }
 
-impl<'a, S: Span> OpDelimitedIter<'a, S> {
+impl<'a> OpDelimitedIter<'a> {
     fn is_eof(&self) -> bool {
         let len = self.inner.len()
             + if self.delimited.kind != tt::DelimiterKind::Invisible { 2 } else { 0 };
         self.idx >= len
     }
 
-    fn peek(&self) -> Option<OpDelimited<'a, S>> {
+    fn peek(&self) -> Option<OpDelimited<'a>> {
         match self.delimited.kind {
             tt::DelimiterKind::Invisible => self.inner.get(self.idx).map(OpDelimited::Op),
             _ => match self.idx {
@@ -909,8 +885,8 @@ impl<'a, S: Span> OpDelimitedIter<'a, S> {
     }
 }
 
-impl<'a, S: Span> Iterator for OpDelimitedIter<'a, S> {
-    type Item = OpDelimited<'a, S>;
+impl<'a> Iterator for OpDelimitedIter<'a> {
+    type Item = OpDelimited<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
         let res = self.peek();
@@ -926,8 +902,8 @@ impl<'a, S: Span> Iterator for OpDelimitedIter<'a, S> {
     }
 }
 
-impl<S: Span> TtIter<'_, S> {
-    fn expect_separator(&mut self, separator: &Separator<S>) -> bool {
+impl TtIter<'_, Span> {
+    fn expect_separator(&mut self, separator: &Separator) -> bool {
         let mut fork = self.clone();
         let ok = match separator {
             Separator::Ident(lhs) => match fork.expect_ident_or_underscore() {
@@ -957,7 +933,7 @@ impl<S: Span> TtIter<'_, S> {
         ok
     }
 
-    fn expect_tt(&mut self) -> Result<tt::TokenTree<S>, ()> {
+    fn expect_tt(&mut self) -> Result<tt::TokenTree<Span>, ()> {
         if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = self.peek_n(0) {
             if punct.char == '\'' {
                 self.expect_lifetime()
@@ -976,7 +952,7 @@ impl<S: Span> TtIter<'_, S> {
         }
     }
 
-    fn expect_lifetime(&mut self) -> Result<tt::TokenTree<S>, ()> {
+    fn expect_lifetime(&mut self) -> Result<tt::TokenTree<Span>, ()> {
         let punct = self.expect_single_punct()?;
         if punct.char != '\'' {
             return Err(());
@@ -997,7 +973,7 @@ impl<S: Span> TtIter<'_, S> {
         .into())
     }
 
-    fn eat_char(&mut self, c: char) -> Option<tt::TokenTree<S>> {
+    fn eat_char(&mut self, c: char) -> Option<tt::TokenTree<Span>> {
         let mut fork = self.clone();
         match fork.expect_char(c) {
             Ok(_) => {
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
index 6d3055da286..5e6e45f1521 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
@@ -1,8 +1,9 @@
 //! Transcriber takes a template, like `fn $ident() {}`, a set of bindings like
 //! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}`
 
+use span::Span;
 use syntax::SmolStr;
-use tt::{Delimiter, Span};
+use tt::Delimiter;
 
 use crate::{
     expander::{Binding, Bindings, Fragment},
@@ -10,8 +11,8 @@ use crate::{
     CountError, ExpandError, ExpandResult, MetaTemplate,
 };
 
-impl<S: Span> Bindings<S> {
-    fn get(&self, name: &str) -> Result<&Binding<S>, ExpandError> {
+impl Bindings {
+    fn get(&self, name: &str) -> Result<&Binding, ExpandError> {
         match self.inner.get(name) {
             Some(binding) => Ok(binding),
             None => Err(ExpandError::UnresolvedBinding(Box::new(Box::from(name)))),
@@ -21,10 +22,10 @@ impl<S: Span> Bindings<S> {
     fn get_fragment(
         &self,
         name: &str,
-        mut span: S,
+        mut span: Span,
         nesting: &mut [NestingState],
-        marker: impl Fn(&mut S),
-    ) -> Result<Fragment<S>, ExpandError> {
+        marker: impl Fn(&mut Span),
+    ) -> Result<Fragment, ExpandError> {
         macro_rules! binding_err {
             ($($arg:tt)*) => { ExpandError::binding_error(format!($($arg)*)) };
         }
@@ -134,15 +135,15 @@ impl<S: Span> Bindings<S> {
     }
 }
 
-pub(super) fn transcribe<S: Span>(
-    template: &MetaTemplate<S>,
-    bindings: &Bindings<S>,
-    marker: impl Fn(&mut S) + Copy,
+pub(super) fn transcribe(
+    template: &MetaTemplate,
+    bindings: &Bindings,
+    marker: impl Fn(&mut Span) + Copy,
     new_meta_vars: bool,
-    call_site: S,
-) -> ExpandResult<tt::Subtree<S>> {
+    call_site: Span,
+) -> ExpandResult<tt::Subtree<Span>> {
     let mut ctx = ExpandCtx { bindings, nesting: Vec::new(), new_meta_vars, call_site };
-    let mut arena: Vec<tt::TokenTree<S>> = Vec::new();
+    let mut arena: Vec<tt::TokenTree<Span>> = Vec::new();
     expand_subtree(&mut ctx, template, None, &mut arena, marker)
 }
 
@@ -158,20 +159,20 @@ struct NestingState {
 }
 
 #[derive(Debug)]
-struct ExpandCtx<'a, S> {
-    bindings: &'a Bindings<S>,
+struct ExpandCtx<'a> {
+    bindings: &'a Bindings,
     nesting: Vec<NestingState>,
     new_meta_vars: bool,
-    call_site: S,
+    call_site: Span,
 }
 
-fn expand_subtree<S: Span>(
-    ctx: &mut ExpandCtx<'_, S>,
-    template: &MetaTemplate<S>,
-    delimiter: Option<Delimiter<S>>,
-    arena: &mut Vec<tt::TokenTree<S>>,
-    marker: impl Fn(&mut S) + Copy,
-) -> ExpandResult<tt::Subtree<S>> {
+fn expand_subtree(
+    ctx: &mut ExpandCtx<'_>,
+    template: &MetaTemplate,
+    delimiter: Option<Delimiter<Span>>,
+    arena: &mut Vec<tt::TokenTree<Span>>,
+    marker: impl Fn(&mut Span) + Copy,
+) -> ExpandResult<tt::Subtree<Span>> {
     // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation
     let start_elements = arena.len();
     let mut err = None;
@@ -332,12 +333,12 @@ fn expand_subtree<S: Span>(
     }
 }
 
-fn expand_var<S: Span>(
-    ctx: &mut ExpandCtx<'_, S>,
+fn expand_var(
+    ctx: &mut ExpandCtx<'_>,
     v: &SmolStr,
-    id: S,
-    marker: impl Fn(&mut S),
-) -> ExpandResult<Fragment<S>> {
+    id: Span,
+    marker: impl Fn(&mut Span),
+) -> ExpandResult<Fragment> {
     // We already handle $crate case in mbe parser
     debug_assert!(v != "crate");
 
@@ -378,15 +379,15 @@ fn expand_var<S: Span>(
     }
 }
 
-fn expand_repeat<S: Span>(
-    ctx: &mut ExpandCtx<'_, S>,
-    template: &MetaTemplate<S>,
+fn expand_repeat(
+    ctx: &mut ExpandCtx<'_>,
+    template: &MetaTemplate,
     kind: RepeatKind,
-    separator: &Option<Separator<S>>,
-    arena: &mut Vec<tt::TokenTree<S>>,
-    marker: impl Fn(&mut S) + Copy,
-) -> ExpandResult<Fragment<S>> {
-    let mut buf: Vec<tt::TokenTree<S>> = Vec::new();
+    separator: &Option<Separator>,
+    arena: &mut Vec<tt::TokenTree<Span>>,
+    marker: impl Fn(&mut Span) + Copy,
+) -> ExpandResult<Fragment> {
+    let mut buf: Vec<tt::TokenTree<Span>> = Vec::new();
     ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false });
     // Dirty hack to make macro-expansion terminate.
     // This should be replaced by a proper macro-by-example implementation
@@ -478,11 +479,7 @@ fn expand_repeat<S: Span>(
     ExpandResult { value: Fragment::Tokens(tt), err }
 }
 
-fn push_fragment<S: Span>(
-    ctx: &ExpandCtx<'_, S>,
-    buf: &mut Vec<tt::TokenTree<S>>,
-    fragment: Fragment<S>,
-) {
+fn push_fragment(ctx: &ExpandCtx<'_>, buf: &mut Vec<tt::TokenTree<Span>>, fragment: Fragment) {
     match fragment {
         Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt),
         Fragment::Expr(sub) => {
@@ -494,7 +491,7 @@ fn push_fragment<S: Span>(
     }
 }
 
-fn push_subtree<S>(buf: &mut Vec<tt::TokenTree<S>>, tt: tt::Subtree<S>) {
+fn push_subtree(buf: &mut Vec<tt::TokenTree<Span>>, tt: tt::Subtree<Span>) {
     match tt.delimiter.kind {
         tt::DelimiterKind::Invisible => buf.extend(Vec::from(tt.token_trees)),
         _ => buf.push(tt.into()),
@@ -504,10 +501,10 @@ fn push_subtree<S>(buf: &mut Vec<tt::TokenTree<S>>, tt: tt::Subtree<S>) {
 /// Inserts the path separator `::` between an identifier and its following generic
 /// argument list, and then pushes into the buffer. See [`Fragment::Path`] for why
 /// we need this fixup.
-fn fix_up_and_push_path_tt<S: Span>(
-    ctx: &ExpandCtx<'_, S>,
-    buf: &mut Vec<tt::TokenTree<S>>,
-    subtree: tt::Subtree<S>,
+fn fix_up_and_push_path_tt(
+    ctx: &ExpandCtx<'_>,
+    buf: &mut Vec<tt::TokenTree<Span>>,
+    subtree: tt::Subtree<Span>,
 ) {
     stdx::always!(matches!(subtree.delimiter.kind, tt::DelimiterKind::Invisible));
     let mut prev_was_ident = false;
@@ -546,11 +543,7 @@ fn fix_up_and_push_path_tt<S: Span>(
 
 /// Handles `${count(t, depth)}`. `our_depth` is the recursion depth and `count_depth` is the depth
 /// defined by the metavar expression.
-fn count<S>(
-    binding: &Binding<S>,
-    depth_curr: usize,
-    depth_max: usize,
-) -> Result<usize, CountError> {
+fn count(binding: &Binding, depth_curr: usize, depth_max: usize) -> Result<usize, CountError> {
     match binding {
         Binding::Nested(bs) => {
             if depth_curr == depth_max {
@@ -564,8 +557,8 @@ fn count<S>(
     }
 }
 
-fn count_old<S>(
-    binding: &Binding<S>,
+fn count_old(
+    binding: &Binding,
     our_depth: usize,
     count_depth: Option<usize>,
 ) -> Result<usize, CountError> {
diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
index 62fdce36892..3a853512660 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
@@ -17,8 +17,8 @@ mod tt_iter;
 #[cfg(test)]
 mod benchmark;
 
+use span::{Edition, Span, SyntaxContextId};
 use stdx::impl_from;
-use tt::Span;
 
 use std::fmt;
 
@@ -127,32 +127,29 @@ impl fmt::Display for CountError {
 /// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident`
 /// and `$()*` have special meaning (see `Var` and `Repeat` data structures)
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub struct DeclarativeMacro<S> {
-    rules: Box<[Rule<S>]>,
-    // This is used for correctly determining the behavior of the pat fragment
-    // FIXME: This should be tracked by hygiene of the fragment identifier!
-    is_2021: bool,
+pub struct DeclarativeMacro {
+    rules: Box<[Rule]>,
     err: Option<Box<ParseError>>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-struct Rule<S> {
-    lhs: MetaTemplate<S>,
-    rhs: MetaTemplate<S>,
+struct Rule {
+    lhs: MetaTemplate,
+    rhs: MetaTemplate,
 }
 
-impl<S: Span> DeclarativeMacro<S> {
-    pub fn from_err(err: ParseError, is_2021: bool) -> DeclarativeMacro<S> {
-        DeclarativeMacro { rules: Box::default(), is_2021, err: Some(Box::new(err)) }
+impl DeclarativeMacro {
+    pub fn from_err(err: ParseError) -> DeclarativeMacro {
+        DeclarativeMacro { rules: Box::default(), err: Some(Box::new(err)) }
     }
 
     /// The old, `macro_rules! m {}` flavor.
     pub fn parse_macro_rules(
-        tt: &tt::Subtree<S>,
-        is_2021: bool,
+        tt: &tt::Subtree<Span>,
+        edition: impl Copy + Fn(SyntaxContextId) -> Edition,
         // FIXME: Remove this once we drop support for rust 1.76 (defaults to true then)
         new_meta_vars: bool,
-    ) -> DeclarativeMacro<S> {
+    ) -> DeclarativeMacro {
         // Note: this parsing can be implemented using mbe machinery itself, by
         // matching against `$($lhs:tt => $rhs:tt);*` pattern, but implementing
         // manually seems easier.
@@ -161,7 +158,7 @@ impl<S: Span> DeclarativeMacro<S> {
         let mut err = None;
 
         while src.len() > 0 {
-            let rule = match Rule::parse(&mut src, true, new_meta_vars) {
+            let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) {
                 Ok(it) => it,
                 Err(e) => {
                     err = Some(Box::new(e));
@@ -184,16 +181,16 @@ impl<S: Span> DeclarativeMacro<S> {
             }
         }
 
-        DeclarativeMacro { rules: rules.into_boxed_slice(), is_2021, err }
+        DeclarativeMacro { rules: rules.into_boxed_slice(), err }
     }
 
     /// The new, unstable `macro m {}` flavor.
     pub fn parse_macro2(
-        tt: &tt::Subtree<S>,
-        is_2021: bool,
+        tt: &tt::Subtree<Span>,
+        edition: impl Copy + Fn(SyntaxContextId) -> Edition,
         // FIXME: Remove this once we drop support for rust 1.76 (defaults to true then)
         new_meta_vars: bool,
-    ) -> DeclarativeMacro<S> {
+    ) -> DeclarativeMacro {
         let mut src = TtIter::new(tt);
         let mut rules = Vec::new();
         let mut err = None;
@@ -201,7 +198,7 @@ impl<S: Span> DeclarativeMacro<S> {
         if tt::DelimiterKind::Brace == tt.delimiter.kind {
             cov_mark::hit!(parse_macro_def_rules);
             while src.len() > 0 {
-                let rule = match Rule::parse(&mut src, true, new_meta_vars) {
+                let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) {
                     Ok(it) => it,
                     Err(e) => {
                         err = Some(Box::new(e));
@@ -220,7 +217,7 @@ impl<S: Span> DeclarativeMacro<S> {
             }
         } else {
             cov_mark::hit!(parse_macro_def_simple);
-            match Rule::parse(&mut src, false, new_meta_vars) {
+            match Rule::parse(edition, &mut src, false, new_meta_vars) {
                 Ok(rule) => {
                     if src.len() != 0 {
                         err = Some(Box::new(ParseError::expected("remaining tokens in macro def")));
@@ -240,7 +237,7 @@ impl<S: Span> DeclarativeMacro<S> {
             }
         }
 
-        DeclarativeMacro { rules: rules.into_boxed_slice(), is_2021, err }
+        DeclarativeMacro { rules: rules.into_boxed_slice(), err }
     }
 
     pub fn err(&self) -> Option<&ParseError> {
@@ -249,18 +246,19 @@ impl<S: Span> DeclarativeMacro<S> {
 
     pub fn expand(
         &self,
-        tt: &tt::Subtree<S>,
-        marker: impl Fn(&mut S) + Copy,
+        tt: &tt::Subtree<Span>,
+        marker: impl Fn(&mut Span) + Copy,
         new_meta_vars: bool,
-        call_site: S,
-    ) -> ExpandResult<tt::Subtree<S>> {
-        expander::expand_rules(&self.rules, tt, marker, self.is_2021, new_meta_vars, call_site)
+        call_site: Span,
+    ) -> ExpandResult<tt::Subtree<Span>> {
+        expander::expand_rules(&self.rules, tt, marker, new_meta_vars, call_site)
     }
 }
 
-impl<S: Span> Rule<S> {
+impl Rule {
     fn parse(
-        src: &mut TtIter<'_, S>,
+        edition: impl Copy + Fn(SyntaxContextId) -> Edition,
+        src: &mut TtIter<'_, Span>,
         expect_arrow: bool,
         new_meta_vars: bool,
     ) -> Result<Self, ParseError> {
@@ -271,14 +269,14 @@ impl<S: Span> Rule<S> {
         }
         let rhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?;
 
-        let lhs = MetaTemplate::parse_pattern(lhs)?;
-        let rhs = MetaTemplate::parse_template(rhs, new_meta_vars)?;
+        let lhs = MetaTemplate::parse_pattern(edition, lhs)?;
+        let rhs = MetaTemplate::parse_template(edition, rhs, new_meta_vars)?;
 
         Ok(crate::Rule { lhs, rhs })
     }
 }
 
-fn validate<S: Span>(pattern: &MetaTemplate<S>) -> Result<(), ParseError> {
+fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> {
     for op in pattern.iter() {
         match op {
             Op::Subtree { tokens, .. } => validate(tokens)?,
diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs
index afdbbef2314..eaf2fd8c273 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/parser.rs
@@ -2,8 +2,8 @@
 //! trees.
 
 use smallvec::{smallvec, SmallVec};
+use span::{Edition, Span, SyntaxContextId};
 use syntax::SmolStr;
-use tt::Span;
 
 use crate::{tt_iter::TtIter, ParseError};
 
@@ -21,30 +21,39 @@ use crate::{tt_iter::TtIter, ParseError};
 /// Stuff to the right is a [`MetaTemplate`] template which is used to produce
 /// output.
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub(crate) struct MetaTemplate<S>(pub(crate) Box<[Op<S>]>);
+pub(crate) struct MetaTemplate(pub(crate) Box<[Op]>);
 
-impl<S: Span> MetaTemplate<S> {
-    pub(crate) fn parse_pattern(pattern: &tt::Subtree<S>) -> Result<Self, ParseError> {
-        MetaTemplate::parse(pattern, Mode::Pattern, false)
+impl MetaTemplate {
+    pub(crate) fn parse_pattern(
+        edition: impl Copy + Fn(SyntaxContextId) -> Edition,
+        pattern: &tt::Subtree<Span>,
+    ) -> Result<Self, ParseError> {
+        MetaTemplate::parse(edition, pattern, Mode::Pattern, false)
     }
 
     pub(crate) fn parse_template(
-        template: &tt::Subtree<S>,
+        edition: impl Copy + Fn(SyntaxContextId) -> Edition,
+        template: &tt::Subtree<Span>,
         new_meta_vars: bool,
     ) -> Result<Self, ParseError> {
-        MetaTemplate::parse(template, Mode::Template, new_meta_vars)
+        MetaTemplate::parse(edition, template, Mode::Template, new_meta_vars)
     }
 
-    pub(crate) fn iter(&self) -> impl Iterator<Item = &Op<S>> {
+    pub(crate) fn iter(&self) -> impl Iterator<Item = &Op> {
         self.0.iter()
     }
 
-    fn parse(tt: &tt::Subtree<S>, mode: Mode, new_meta_vars: bool) -> Result<Self, ParseError> {
+    fn parse(
+        edition: impl Copy + Fn(SyntaxContextId) -> Edition,
+        tt: &tt::Subtree<Span>,
+        mode: Mode,
+        new_meta_vars: bool,
+    ) -> Result<Self, ParseError> {
         let mut src = TtIter::new(tt);
 
         let mut res = Vec::new();
         while let Some(first) = src.peek_n(0) {
-            let op = next_op(first, &mut src, mode, new_meta_vars)?;
+            let op = next_op(edition, first, &mut src, mode, new_meta_vars)?;
             res.push(op);
         }
 
@@ -53,15 +62,15 @@ impl<S: Span> MetaTemplate<S> {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub(crate) enum Op<S> {
+pub(crate) enum Op {
     Var {
         name: SmolStr,
         kind: Option<MetaVarKind>,
-        id: S,
+        id: Span,
     },
     Ignore {
         name: SmolStr,
-        id: S,
+        id: Span,
     },
     Index {
         depth: usize,
@@ -75,17 +84,17 @@ pub(crate) enum Op<S> {
         depth: Option<usize>,
     },
     Repeat {
-        tokens: MetaTemplate<S>,
+        tokens: MetaTemplate,
         kind: RepeatKind,
-        separator: Option<Separator<S>>,
+        separator: Option<Separator>,
     },
     Subtree {
-        tokens: MetaTemplate<S>,
-        delimiter: tt::Delimiter<S>,
+        tokens: MetaTemplate,
+        delimiter: tt::Delimiter<Span>,
     },
-    Literal(tt::Literal<S>),
-    Punct(SmallVec<[tt::Punct<S>; 3]>),
-    Ident(tt::Ident<S>),
+    Literal(tt::Literal<Span>),
+    Punct(SmallVec<[tt::Punct<Span>; 3]>),
+    Ident(tt::Ident<Span>),
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -114,15 +123,15 @@ pub(crate) enum MetaVarKind {
 }
 
 #[derive(Clone, Debug, Eq)]
-pub(crate) enum Separator<S> {
-    Literal(tt::Literal<S>),
-    Ident(tt::Ident<S>),
-    Puncts(SmallVec<[tt::Punct<S>; 3]>),
+pub(crate) enum Separator {
+    Literal(tt::Literal<Span>),
+    Ident(tt::Ident<Span>),
+    Puncts(SmallVec<[tt::Punct<Span>; 3]>),
 }
 
 // Note that when we compare a Separator, we just care about its textual value.
-impl<S> PartialEq for Separator<S> {
-    fn eq(&self, other: &Separator<S>) -> bool {
+impl PartialEq for Separator {
+    fn eq(&self, other: &Separator) -> bool {
         use Separator::*;
 
         match (self, other) {
@@ -144,12 +153,13 @@ enum Mode {
     Template,
 }
 
-fn next_op<S: Span>(
-    first_peeked: &tt::TokenTree<S>,
-    src: &mut TtIter<'_, S>,
+fn next_op(
+    edition: impl Copy + Fn(SyntaxContextId) -> Edition,
+    first_peeked: &tt::TokenTree<Span>,
+    src: &mut TtIter<'_, Span>,
     mode: Mode,
     new_meta_vars: bool,
-) -> Result<Op<S>, ParseError> {
+) -> Result<Op, ParseError> {
     let res = match first_peeked {
         tt::TokenTree::Leaf(tt::Leaf::Punct(p @ tt::Punct { char: '$', .. })) => {
             src.next().expect("first token already peeked");
@@ -162,7 +172,7 @@ fn next_op<S: Span>(
                 tt::TokenTree::Subtree(subtree) => match subtree.delimiter.kind {
                     tt::DelimiterKind::Parenthesis => {
                         let (separator, kind) = parse_repeat(src)?;
-                        let tokens = MetaTemplate::parse(subtree, mode, new_meta_vars)?;
+                        let tokens = MetaTemplate::parse(edition, subtree, mode, new_meta_vars)?;
                         Op::Repeat { tokens, separator, kind }
                     }
                     tt::DelimiterKind::Brace => match mode {
@@ -189,13 +199,13 @@ fn next_op<S: Span>(
                         Op::Ident(tt::Ident { text: "$crate".into(), span: ident.span })
                     }
                     tt::Leaf::Ident(ident) => {
-                        let kind = eat_fragment_kind(src, mode)?;
+                        let kind = eat_fragment_kind(edition, src, mode)?;
                         let name = ident.text.clone();
                         let id = ident.span;
                         Op::Var { name, kind, id }
                     }
                     tt::Leaf::Literal(lit) if is_boolean_literal(lit) => {
-                        let kind = eat_fragment_kind(src, mode)?;
+                        let kind = eat_fragment_kind(edition, src, mode)?;
                         let name = lit.text.clone();
                         let id = lit.span;
                         Op::Var { name, kind, id }
@@ -233,15 +243,16 @@ fn next_op<S: Span>(
 
         tt::TokenTree::Subtree(subtree) => {
             src.next().expect("first token already peeked");
-            let tokens = MetaTemplate::parse(subtree, mode, new_meta_vars)?;
+            let tokens = MetaTemplate::parse(edition, subtree, mode, new_meta_vars)?;
             Op::Subtree { tokens, delimiter: subtree.delimiter }
         }
     };
     Ok(res)
 }
 
-fn eat_fragment_kind<S: Span>(
-    src: &mut TtIter<'_, S>,
+fn eat_fragment_kind(
+    edition: impl Copy + Fn(SyntaxContextId) -> Edition,
+    src: &mut TtIter<'_, Span>,
     mode: Mode,
 ) -> Result<Option<MetaVarKind>, ParseError> {
     if let Mode::Pattern = mode {
@@ -252,7 +263,10 @@ fn eat_fragment_kind<S: Span>(
         let kind = match ident.text.as_str() {
             "path" => MetaVarKind::Path,
             "ty" => MetaVarKind::Ty,
-            "pat" => MetaVarKind::Pat,
+            "pat" => match edition(ident.span.ctx) {
+                Edition::Edition2015 | Edition::Edition2018 => MetaVarKind::PatParam,
+                Edition::Edition2021 | Edition::Edition2024 => MetaVarKind::Pat,
+            },
             "pat_param" => MetaVarKind::PatParam,
             "stmt" => MetaVarKind::Stmt,
             "block" => MetaVarKind::Block,
@@ -271,13 +285,11 @@ fn eat_fragment_kind<S: Span>(
     Ok(None)
 }
 
-fn is_boolean_literal<S>(lit: &tt::Literal<S>) -> bool {
+fn is_boolean_literal(lit: &tt::Literal<Span>) -> bool {
     matches!(lit.text.as_str(), "true" | "false")
 }
 
-fn parse_repeat<S: Span>(
-    src: &mut TtIter<'_, S>,
-) -> Result<(Option<Separator<S>>, RepeatKind), ParseError> {
+fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, RepeatKind), ParseError> {
     let mut separator = Separator::Puncts(SmallVec::new());
     for tt in src {
         let tt = match tt {
@@ -314,7 +326,7 @@ fn parse_repeat<S: Span>(
     Err(ParseError::InvalidRepeat)
 }
 
-fn parse_metavar_expr<S: Span>(new_meta_vars: bool, src: &mut TtIter<'_, S>) -> Result<Op<S>, ()> {
+fn parse_metavar_expr(new_meta_vars: bool, src: &mut TtIter<'_, Span>) -> Result<Op, ()> {
     let func = src.expect_ident()?;
     let args = src.expect_subtree()?;
 
@@ -352,7 +364,7 @@ fn parse_metavar_expr<S: Span>(new_meta_vars: bool, src: &mut TtIter<'_, S>) ->
     Ok(op)
 }
 
-fn parse_depth<S: Span>(src: &mut TtIter<'_, S>) -> Result<usize, ()> {
+fn parse_depth(src: &mut TtIter<'_, Span>) -> Result<usize, ()> {
     if src.len() == 0 {
         Ok(0)
     } else if let tt::Leaf::Literal(lit) = src.expect_literal()? {
@@ -363,7 +375,7 @@ fn parse_depth<S: Span>(src: &mut TtIter<'_, S>) -> Result<usize, ()> {
     }
 }
 
-fn try_eat_comma<S: Span>(src: &mut TtIter<'_, S>) -> bool {
+fn try_eat_comma(src: &mut TtIter<'_, Span>) -> bool {
     if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', .. }))) = src.peek_n(0) {
         let _ = src.next();
         return true;
diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
index 57d6082dd70..c934db6b715 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
@@ -1,5 +1,7 @@
 //! Conversions between [`SyntaxNode`] and [`tt::TokenTree`].
 
+use std::fmt;
+
 use rustc_hash::{FxHashMap, FxHashSet};
 use span::{SpanAnchor, SpanData, SpanMap};
 use stdx::{never, non_empty_vec::NonEmptyVec};
@@ -9,30 +11,27 @@ use syntax::{
     SyntaxKind::*,
     SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, WalkEvent, T,
 };
-use tt::{
-    buffer::{Cursor, TokenBuffer},
-    Span,
-};
+use tt::buffer::{Cursor, TokenBuffer};
 
 use crate::{to_parser_input::to_parser_input, tt_iter::TtIter};
 
 #[cfg(test)]
 mod tests;
 
-pub trait SpanMapper<S: Span> {
+pub trait SpanMapper<S> {
     fn span_for(&self, range: TextRange) -> S;
 }
 
 impl<S> SpanMapper<SpanData<S>> for SpanMap<S>
 where
-    SpanData<S>: Span,
+    SpanData<S>: Copy,
 {
     fn span_for(&self, range: TextRange) -> SpanData<S> {
         self.span_at(range.start())
     }
 }
 
-impl<S: Span, SM: SpanMapper<S>> SpanMapper<S> for &SM {
+impl<S: Copy, SM: SpanMapper<S>> SpanMapper<S> for &SM {
     fn span_for(&self, range: TextRange) -> S {
         SM::span_for(self, range)
     }
@@ -78,8 +77,7 @@ pub fn syntax_node_to_token_tree<Ctx, SpanMap>(
     span: SpanData<Ctx>,
 ) -> tt::Subtree<SpanData<Ctx>>
 where
-    SpanData<Ctx>: Span,
-    Ctx: Copy,
+    SpanData<Ctx>: Copy + fmt::Debug,
     SpanMap: SpanMapper<SpanData<Ctx>>,
 {
     let mut c = Converter::new(node, map, Default::default(), Default::default(), span);
@@ -98,8 +96,7 @@ pub fn syntax_node_to_token_tree_modified<Ctx, SpanMap>(
 ) -> tt::Subtree<SpanData<Ctx>>
 where
     SpanMap: SpanMapper<SpanData<Ctx>>,
-    SpanData<Ctx>: Span,
-    Ctx: Copy,
+    SpanData<Ctx>: Copy + fmt::Debug,
 {
     let mut c = Converter::new(node, map, append, remove, call_site);
     convert_tokens(&mut c)
@@ -124,8 +121,7 @@ pub fn token_tree_to_syntax_node<Ctx>(
     entry_point: parser::TopEntryPoint,
 ) -> (Parse<SyntaxNode>, SpanMap<Ctx>)
 where
-    SpanData<Ctx>: Span,
-    Ctx: Copy,
+    SpanData<Ctx>: Copy + fmt::Debug,
 {
     let buffer = match tt {
         tt::Subtree {
@@ -161,7 +157,7 @@ pub fn parse_to_token_tree<Ctx>(
     text: &str,
 ) -> Option<tt::Subtree<SpanData<Ctx>>>
 where
-    SpanData<Ctx>: Span,
+    SpanData<Ctx>: Copy + fmt::Debug,
     Ctx: Copy,
 {
     let lexed = parser::LexedStr::new(text);
@@ -175,7 +171,7 @@ where
 /// Convert a string to a `TokenTree`. The passed span will be used for all spans of the produced subtree.
 pub fn parse_to_token_tree_static_span<S>(span: S, text: &str) -> Option<tt::Subtree<S>>
 where
-    S: Span,
+    S: Copy + fmt::Debug,
 {
     let lexed = parser::LexedStr::new(text);
     if lexed.errors().next().is_some() {
@@ -186,11 +182,10 @@ where
 }
 
 /// Split token tree with separate expr: $($e:expr)SEP*
-pub fn parse_exprs_with_sep<S: Span>(
-    tt: &tt::Subtree<S>,
-    sep: char,
-    span: S,
-) -> Vec<tt::Subtree<S>> {
+pub fn parse_exprs_with_sep<S>(tt: &tt::Subtree<S>, sep: char, span: S) -> Vec<tt::Subtree<S>>
+where
+    S: Copy + fmt::Debug,
+{
     if tt.token_trees.is_empty() {
         return Vec::new();
     }
@@ -226,7 +221,8 @@ pub fn parse_exprs_with_sep<S: Span>(
 fn convert_tokens<S, C>(conv: &mut C) -> tt::Subtree<S>
 where
     C: TokenConverter<S>,
-    S: Span,
+    S: Copy + fmt::Debug,
+    C::Token: fmt::Debug,
 {
     let entry = tt::SubtreeBuilder {
         delimiter: tt::Delimiter::invisible_spanned(conv.call_site()),
@@ -485,7 +481,7 @@ struct StaticRawConverter<'a, S> {
     span: S,
 }
 
-trait SrcToken<Ctx, S>: std::fmt::Debug {
+trait SrcToken<Ctx, S> {
     fn kind(&self, ctx: &Ctx) -> SyntaxKind;
 
     fn to_char(&self, ctx: &Ctx) -> Option<char>;
@@ -525,7 +521,7 @@ impl<S, Ctx> SrcToken<RawConverter<'_, Ctx>, S> for usize {
     }
 }
 
-impl<S: Span> SrcToken<StaticRawConverter<'_, S>, S> for usize {
+impl<S: Copy> SrcToken<StaticRawConverter<'_, S>, S> for usize {
     fn kind(&self, ctx: &StaticRawConverter<'_, S>) -> SyntaxKind {
         ctx.lexed.kind(*self)
     }
@@ -541,7 +537,7 @@ impl<S: Span> SrcToken<StaticRawConverter<'_, S>, S> for usize {
 
 impl<Ctx: Copy> TokenConverter<SpanData<Ctx>> for RawConverter<'_, Ctx>
 where
-    SpanData<Ctx>: Span,
+    SpanData<Ctx>: Copy,
 {
     type Token = usize;
 
@@ -584,7 +580,7 @@ where
 
 impl<S> TokenConverter<S> for StaticRawConverter<'_, S>
 where
-    S: Span,
+    S: Copy,
 {
     type Token = usize;
 
@@ -709,7 +705,7 @@ impl<S> SynToken<S> {
     }
 }
 
-impl<SpanMap, S: std::fmt::Debug> SrcToken<Converter<SpanMap, S>, S> for SynToken<S> {
+impl<SpanMap, S> SrcToken<Converter<SpanMap, S>, S> for SynToken<S> {
     fn kind(&self, _ctx: &Converter<SpanMap, S>) -> SyntaxKind {
         match self {
             SynToken::Ordinary(token) => token.kind(),
@@ -748,7 +744,7 @@ impl<SpanMap, S: std::fmt::Debug> SrcToken<Converter<SpanMap, S>, S> for SynToke
 
 impl<S, SpanMap> TokenConverter<S> for Converter<SpanMap, S>
 where
-    S: Span,
+    S: Copy,
     SpanMap: SpanMapper<S>,
 {
     type Token = SynToken<S>;
@@ -828,7 +824,7 @@ where
 
 struct TtTreeSink<'a, Ctx>
 where
-    SpanData<Ctx>: Span,
+    SpanData<Ctx>: Copy,
 {
     buf: String,
     cursor: Cursor<'a, SpanData<Ctx>>,
@@ -839,7 +835,7 @@ where
 
 impl<'a, Ctx> TtTreeSink<'a, Ctx>
 where
-    SpanData<Ctx>: Span,
+    SpanData<Ctx>: Copy,
 {
     fn new(cursor: Cursor<'a, SpanData<Ctx>>) -> Self {
         TtTreeSink {
@@ -871,7 +867,7 @@ fn delim_to_str(d: tt::DelimiterKind, closing: bool) -> Option<&'static str> {
 
 impl<Ctx> TtTreeSink<'_, Ctx>
 where
-    SpanData<Ctx>: Span,
+    SpanData<Ctx>: Copy,
 {
     /// Parses a float literal as if it was a one to two name ref nodes with a dot inbetween.
     /// This occurs when a float literal is used as a field access.
diff --git a/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs b/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs
index 00a14f04686..3f70149aa5e 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs
@@ -1,11 +1,13 @@
 //! Convert macro-by-example tokens which are specific to macro expansion into a
 //! format that works for our parser.
 
+use std::fmt;
+
 use syntax::{SyntaxKind, SyntaxKind::*, T};
 
-use tt::{buffer::TokenBuffer, Span};
+use tt::buffer::TokenBuffer;
 
-pub(crate) fn to_parser_input<S: Span>(buffer: &TokenBuffer<'_, S>) -> parser::Input {
+pub(crate) fn to_parser_input<S: Copy + fmt::Debug>(buffer: &TokenBuffer<'_, S>) -> parser::Input {
     let mut res = parser::Input::default();
 
     let mut current = buffer.begin();
diff --git a/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs b/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs
index f9913cb6f9b..e3d12d87078 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs
@@ -1,9 +1,10 @@
 //! A "Parser" structure for token trees. We use this when parsing a declarative
 //! macro definition into a list of patterns and templates.
 
+use core::fmt;
+
 use smallvec::{smallvec, SmallVec};
 use syntax::SyntaxKind;
-use tt::Span;
 
 use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult};
 
@@ -12,7 +13,7 @@ pub(crate) struct TtIter<'a, S> {
     pub(crate) inner: std::slice::Iter<'a, tt::TokenTree<S>>,
 }
 
-impl<'a, S: Span> TtIter<'a, S> {
+impl<'a, S: Copy> TtIter<'a, S> {
     pub(crate) fn new(subtree: &'a tt::Subtree<S>) -> TtIter<'a, S> {
         TtIter { inner: subtree.token_trees.iter() }
     }
@@ -130,7 +131,12 @@ impl<'a, S: Span> TtIter<'a, S> {
             _ => Ok(smallvec![first]),
         }
     }
+    pub(crate) fn peek_n(&self, n: usize) -> Option<&'a tt::TokenTree<S>> {
+        self.inner.as_slice().get(n)
+    }
+}
 
+impl<'a, S: Copy + fmt::Debug> TtIter<'a, S> {
     pub(crate) fn expect_fragment(
         &mut self,
         entry_point: parser::PrefixEntryPoint,
@@ -185,10 +191,6 @@ impl<'a, S: Span> TtIter<'a, S> {
         };
         ExpandResult { value: res, err }
     }
-
-    pub(crate) fn peek_n(&self, n: usize) -> Option<&'a tt::TokenTree<S>> {
-        self.inner.as_slice().get(n)
-    }
 }
 
 impl<'a, S> Iterator for TtIter<'a, S> {
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
index 72848a1f2b7..54ed5f0ba23 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
@@ -490,6 +490,18 @@ fn match_expr(p: &mut Parser<'_>) -> CompletedMarker {
     m.complete(p, MATCH_EXPR)
 }
 
+// test_err match_arms_recovery
+// fn foo() {
+//     match () {
+//         _ => (),,
+//         _ => ,
+//         _ => (),
+//          => (),
+//         if true => (),
+//         _ => (),
+//         () if => (),
+//     }
+// }
 pub(crate) fn match_arm_list(p: &mut Parser<'_>) {
     assert!(p.at(T!['{']));
     let m = p.start();
@@ -511,6 +523,10 @@ pub(crate) fn match_arm_list(p: &mut Parser<'_>) {
             error_block(p, "expected match arm");
             continue;
         }
+        if p.at(T![,]) {
+            p.err_and_bump("expected pattern");
+            continue;
+        }
         match_arm(p);
     }
     p.expect(T!['}']);
@@ -544,26 +560,30 @@ fn match_arm(p: &mut Parser<'_>) {
     // }
     attributes::outer_attrs(p);
 
-    patterns::pattern_top_r(p, TokenSet::EMPTY);
+    patterns::pattern_top_r(p, TokenSet::new(&[T![=], T![if]]));
     if p.at(T![if]) {
         match_guard(p);
     }
     p.expect(T![=>]);
-    let blocklike = match expr_stmt(p, None) {
-        Some((_, blocklike)) => blocklike,
-        None => BlockLike::NotBlock,
-    };
-
-    // test match_arms_commas
-    // fn foo() {
-    //     match () {
-    //         _ => (),
-    //         _ => {}
-    //         _ => ()
-    //     }
-    // }
-    if !p.eat(T![,]) && !blocklike.is_block() && !p.at(T!['}']) {
-        p.error("expected `,`");
+    if p.eat(T![,]) {
+        p.error("expected expression");
+    } else {
+        let blocklike = match expr_stmt(p, None) {
+            Some((_, blocklike)) => blocklike,
+            None => BlockLike::NotBlock,
+        };
+
+        // test match_arms_commas
+        // fn foo() {
+        //     match () {
+        //         _ => (),
+        //         _ => {}
+        //         _ => ()
+        //     }
+        // }
+        if !p.eat(T![,]) && !blocklike.is_block() && !p.at(T!['}']) {
+            p.error("expected `,`");
+        }
     }
     m.complete(p, MATCH_ARM);
 }
@@ -579,7 +599,11 @@ fn match_guard(p: &mut Parser<'_>) -> CompletedMarker {
     assert!(p.at(T![if]));
     let m = p.start();
     p.bump(T![if]);
-    expr(p);
+    if p.at(T![=]) {
+        p.error("expected expression");
+    } else {
+        expr(p);
+    }
     m.complete(p, MATCH_GUARD)
 }
 
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0034_match_arms_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0034_match_arms_recovery.rast
new file mode 100644
index 00000000000..5b191945e45
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0034_match_arms_recovery.rast
@@ -0,0 +1,113 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        MATCH_EXPR
+          MATCH_KW "match"
+          WHITESPACE " "
+          TUPLE_EXPR
+            L_PAREN "("
+            R_PAREN ")"
+          WHITESPACE " "
+          MATCH_ARM_LIST
+            L_CURLY "{"
+            WHITESPACE "\n        "
+            MATCH_ARM
+              WILDCARD_PAT
+                UNDERSCORE "_"
+              WHITESPACE " "
+              FAT_ARROW "=>"
+              WHITESPACE " "
+              TUPLE_EXPR
+                L_PAREN "("
+                R_PAREN ")"
+              COMMA ","
+            ERROR
+              COMMA ","
+            WHITESPACE "\n        "
+            MATCH_ARM
+              WILDCARD_PAT
+                UNDERSCORE "_"
+              WHITESPACE " "
+              FAT_ARROW "=>"
+              WHITESPACE " "
+              COMMA ","
+            WHITESPACE "\n        "
+            MATCH_ARM
+              WILDCARD_PAT
+                UNDERSCORE "_"
+              WHITESPACE " "
+              FAT_ARROW "=>"
+              WHITESPACE " "
+              TUPLE_EXPR
+                L_PAREN "("
+                R_PAREN ")"
+              COMMA ","
+            WHITESPACE "\n         "
+            MATCH_ARM
+              FAT_ARROW "=>"
+              WHITESPACE " "
+              TUPLE_EXPR
+                L_PAREN "("
+                R_PAREN ")"
+              COMMA ","
+            WHITESPACE "\n        "
+            MATCH_ARM
+              MATCH_GUARD
+                IF_KW "if"
+                WHITESPACE " "
+                LITERAL
+                  TRUE_KW "true"
+              WHITESPACE " "
+              FAT_ARROW "=>"
+              WHITESPACE " "
+              TUPLE_EXPR
+                L_PAREN "("
+                R_PAREN ")"
+              COMMA ","
+            WHITESPACE "\n        "
+            MATCH_ARM
+              WILDCARD_PAT
+                UNDERSCORE "_"
+              WHITESPACE " "
+              FAT_ARROW "=>"
+              WHITESPACE " "
+              TUPLE_EXPR
+                L_PAREN "("
+                R_PAREN ")"
+              COMMA ","
+            WHITESPACE "\n        "
+            MATCH_ARM
+              TUPLE_PAT
+                L_PAREN "("
+                R_PAREN ")"
+              WHITESPACE " "
+              MATCH_GUARD
+                IF_KW "if"
+              WHITESPACE " "
+              FAT_ARROW "=>"
+              WHITESPACE " "
+              TUPLE_EXPR
+                L_PAREN "("
+                R_PAREN ")"
+              COMMA ","
+            WHITESPACE "\n    "
+            R_CURLY "}"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 42: expected pattern
+error 58: expected expression
+error 85: expected pattern
+error 100: expected pattern
+error 145: expected expression
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0034_match_arms_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0034_match_arms_recovery.rs
new file mode 100644
index 00000000000..173103b2e37
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0034_match_arms_recovery.rs
@@ -0,0 +1,11 @@
+fn foo() {
+    match () {
+        _ => (),,
+        _ => ,
+        _ => (),
+         => (),
+        if true => (),
+        _ => (),
+        () if => (),
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/paths/Cargo.toml b/src/tools/rust-analyzer/crates/paths/Cargo.toml
index 3d8752b5a82..59a4ad9a255 100644
--- a/src/tools/rust-analyzer/crates/paths/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/paths/Cargo.toml
@@ -12,10 +12,14 @@ rust-version.workspace = true
 doctest = false
 
 [dependencies]
+camino.workspace = true
 # Adding this dep sadly puts a lot of rust-analyzer crates after the
 # serde-derive crate. Even though we don't activate the derive feature here,
 # someone else in the crate graph certainly does!
 # serde.workspace = true
 
+[features]
+serde1 = ["camino/serde1"]
+
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/src/tools/rust-analyzer/crates/paths/src/lib.rs b/src/tools/rust-analyzer/crates/paths/src/lib.rs
index a63d251c20d..2d3653401d2 100644
--- a/src/tools/rust-analyzer/crates/paths/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/paths/src/lib.rs
@@ -1,4 +1,4 @@
-//! Thin wrappers around `std::path`, distinguishing between absolute and
+//! Thin wrappers around `std::path`/`camino::path`, distinguishing between absolute and
 //! relative paths.
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
@@ -7,16 +7,24 @@ use std::{
     borrow::Borrow,
     ffi::OsStr,
     fmt, ops,
-    path::{Component, Path, PathBuf},
+    path::{Path, PathBuf},
 };
 
-/// Wrapper around an absolute [`PathBuf`].
-#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
-pub struct AbsPathBuf(PathBuf);
+pub use camino::*;
+
+/// Wrapper around an absolute [`Utf8PathBuf`].
+#[derive(Debug, Clone, Ord, PartialOrd, Eq, Hash)]
+pub struct AbsPathBuf(Utf8PathBuf);
+
+impl From<AbsPathBuf> for Utf8PathBuf {
+    fn from(AbsPathBuf(path_buf): AbsPathBuf) -> Utf8PathBuf {
+        path_buf
+    }
+}
 
 impl From<AbsPathBuf> for PathBuf {
     fn from(AbsPathBuf(path_buf): AbsPathBuf) -> PathBuf {
-        path_buf
+        path_buf.into()
     }
 }
 
@@ -27,9 +35,21 @@ impl ops::Deref for AbsPathBuf {
     }
 }
 
+impl AsRef<Utf8Path> for AbsPathBuf {
+    fn as_ref(&self) -> &Utf8Path {
+        self.0.as_path()
+    }
+}
+
+impl AsRef<OsStr> for AbsPathBuf {
+    fn as_ref(&self) -> &OsStr {
+        self.0.as_ref()
+    }
+}
+
 impl AsRef<Path> for AbsPathBuf {
     fn as_ref(&self) -> &Path {
-        self.0.as_path()
+        self.0.as_ref()
     }
 }
 
@@ -45,26 +65,36 @@ impl Borrow<AbsPath> for AbsPathBuf {
     }
 }
 
+impl TryFrom<Utf8PathBuf> for AbsPathBuf {
+    type Error = Utf8PathBuf;
+    fn try_from(path_buf: Utf8PathBuf) -> Result<AbsPathBuf, Utf8PathBuf> {
+        if !path_buf.is_absolute() {
+            return Err(path_buf);
+        }
+        Ok(AbsPathBuf(path_buf))
+    }
+}
+
 impl TryFrom<PathBuf> for AbsPathBuf {
     type Error = PathBuf;
     fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> {
         if !path_buf.is_absolute() {
             return Err(path_buf);
         }
-        Ok(AbsPathBuf(path_buf))
+        Ok(AbsPathBuf(Utf8PathBuf::from_path_buf(path_buf)?))
     }
 }
 
 impl TryFrom<&str> for AbsPathBuf {
-    type Error = PathBuf;
-    fn try_from(path: &str) -> Result<AbsPathBuf, PathBuf> {
-        AbsPathBuf::try_from(PathBuf::from(path))
+    type Error = Utf8PathBuf;
+    fn try_from(path: &str) -> Result<AbsPathBuf, Utf8PathBuf> {
+        AbsPathBuf::try_from(Utf8PathBuf::from(path))
     }
 }
 
-impl PartialEq<AbsPath> for AbsPathBuf {
-    fn eq(&self, other: &AbsPath) -> bool {
-        self.as_path() == other
+impl<P: AsRef<Path> + ?Sized> PartialEq<P> for AbsPathBuf {
+    fn eq(&self, other: &P) -> bool {
+        self.0.as_std_path() == other.as_ref()
     }
 }
 
@@ -74,19 +104,31 @@ impl AbsPathBuf {
     /// # Panics
     ///
     /// Panics if `path` is not absolute.
-    pub fn assert(path: PathBuf) -> AbsPathBuf {
+    pub fn assert(path: Utf8PathBuf) -> AbsPathBuf {
         AbsPathBuf::try_from(path)
-            .unwrap_or_else(|path| panic!("expected absolute path, got {}", path.display()))
+            .unwrap_or_else(|path| panic!("expected absolute path, got {}", path))
+    }
+
+    /// Wrap the given absolute path in `AbsPathBuf`
+    ///
+    /// # Panics
+    ///
+    /// Panics if `path` is not absolute.
+    pub fn assert_utf8(path: PathBuf) -> AbsPathBuf {
+        AbsPathBuf::assert(
+            Utf8PathBuf::from_path_buf(path)
+                .unwrap_or_else(|path| panic!("expected utf8 path, got {}", path.display())),
+        )
     }
 
     /// Coerces to an `AbsPath` slice.
     ///
-    /// Equivalent of [`PathBuf::as_path`] for `AbsPathBuf`.
+    /// Equivalent of [`Utf8PathBuf::as_path`] for `AbsPathBuf`.
     pub fn as_path(&self) -> &AbsPath {
         AbsPath::assert(self.0.as_path())
     }
 
-    /// Equivalent of [`PathBuf::pop`] for `AbsPathBuf`.
+    /// Equivalent of [`Utf8PathBuf::pop`] for `AbsPathBuf`.
     ///
     /// Note that this won't remove the root component, so `self` will still be
     /// absolute.
@@ -97,18 +139,36 @@ impl AbsPathBuf {
 
 impl fmt::Display for AbsPathBuf {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(&self.0.display(), f)
+        fmt::Display::fmt(&self.0, f)
     }
 }
 
-/// Wrapper around an absolute [`Path`].
-#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
+/// Wrapper around an absolute [`Utf8Path`].
+#[derive(Debug, Ord, PartialOrd, Eq, Hash)]
 #[repr(transparent)]
-pub struct AbsPath(Path);
+pub struct AbsPath(Utf8Path);
+
+impl<P: AsRef<Path> + ?Sized> PartialEq<P> for AbsPath {
+    fn eq(&self, other: &P) -> bool {
+        self.0.as_std_path() == other.as_ref()
+    }
+}
+
+impl AsRef<Utf8Path> for AbsPath {
+    fn as_ref(&self) -> &Utf8Path {
+        &self.0
+    }
+}
 
 impl AsRef<Path> for AbsPath {
     fn as_ref(&self) -> &Path {
-        &self.0
+        self.0.as_ref()
+    }
+}
+
+impl AsRef<OsStr> for AbsPath {
+    fn as_ref(&self) -> &OsStr {
+        self.0.as_ref()
     }
 }
 
@@ -120,9 +180,9 @@ impl ToOwned for AbsPath {
     }
 }
 
-impl<'a> TryFrom<&'a Path> for &'a AbsPath {
-    type Error = &'a Path;
-    fn try_from(path: &'a Path) -> Result<&'a AbsPath, &'a Path> {
+impl<'a> TryFrom<&'a Utf8Path> for &'a AbsPath {
+    type Error = &'a Utf8Path;
+    fn try_from(path: &'a Utf8Path) -> Result<&'a AbsPath, &'a Utf8Path> {
         if !path.is_absolute() {
             return Err(path);
         }
@@ -136,24 +196,24 @@ impl AbsPath {
     /// # Panics
     ///
     /// Panics if `path` is not absolute.
-    pub fn assert(path: &Path) -> &AbsPath {
+    pub fn assert(path: &Utf8Path) -> &AbsPath {
         assert!(path.is_absolute());
-        unsafe { &*(path as *const Path as *const AbsPath) }
+        unsafe { &*(path as *const Utf8Path as *const AbsPath) }
     }
 
-    /// Equivalent of [`Path::parent`] for `AbsPath`.
+    /// Equivalent of [`Utf8Path::parent`] for `AbsPath`.
     pub fn parent(&self) -> Option<&AbsPath> {
         self.0.parent().map(AbsPath::assert)
     }
 
-    /// Equivalent of [`Path::join`] for `AbsPath` with an additional normalize step afterwards.
-    pub fn absolutize(&self, path: impl AsRef<Path>) -> AbsPathBuf {
+    /// Equivalent of [`Utf8Path::join`] for `AbsPath` with an additional normalize step afterwards.
+    pub fn absolutize(&self, path: impl AsRef<Utf8Path>) -> AbsPathBuf {
         self.join(path).normalize()
     }
 
-    /// Equivalent of [`Path::join`] for `AbsPath`.
-    pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf {
-        self.as_ref().join(path).try_into().unwrap()
+    /// Equivalent of [`Utf8Path::join`] for `AbsPath`.
+    pub fn join(&self, path: impl AsRef<Utf8Path>) -> AbsPathBuf {
+        Utf8Path::join(self.as_ref(), path).try_into().unwrap()
     }
 
     /// Normalize the given path:
@@ -172,7 +232,7 @@ impl AbsPath {
         AbsPathBuf(normalize_path(&self.0))
     }
 
-    /// Equivalent of [`Path::to_path_buf`] for `AbsPath`.
+    /// Equivalent of [`Utf8Path::to_path_buf`] for `AbsPath`.
     pub fn to_path_buf(&self) -> AbsPathBuf {
         AbsPathBuf::try_from(self.0.to_path_buf()).unwrap()
     }
@@ -181,7 +241,7 @@ impl AbsPath {
         panic!("We explicitly do not provide canonicalization API, as that is almost always a wrong solution, see #14430")
     }
 
-    /// Equivalent of [`Path::strip_prefix`] for `AbsPath`.
+    /// Equivalent of [`Utf8Path::strip_prefix`] for `AbsPath`.
     ///
     /// Returns a relative path.
     pub fn strip_prefix(&self, base: &AbsPath) -> Option<&RelPath> {
@@ -195,57 +255,61 @@ impl AbsPath {
     }
 
     pub fn name_and_extension(&self) -> Option<(&str, Option<&str>)> {
-        Some((
-            self.file_stem()?.to_str()?,
-            self.extension().and_then(|extension| extension.to_str()),
-        ))
+        Some((self.file_stem()?, self.extension()))
     }
 
     // region:delegate-methods
 
-    // Note that we deliberately don't implement `Deref<Target = Path>` here.
+    // Note that we deliberately don't implement `Deref<Target = Utf8Path>` here.
     //
-    // The problem with `Path` is that it directly exposes convenience IO-ing
-    // methods. For example, `Path::exists` delegates to `fs::metadata`.
+    // The problem with `Utf8Path` is that it directly exposes convenience IO-ing
+    // methods. For example, `Utf8Path::exists` delegates to `fs::metadata`.
     //
     // For `AbsPath`, we want to make sure that this is a POD type, and that all
     // IO goes via `fs`. That way, it becomes easier to mock IO when we need it.
 
-    pub fn file_name(&self) -> Option<&OsStr> {
+    pub fn file_name(&self) -> Option<&str> {
         self.0.file_name()
     }
-    pub fn extension(&self) -> Option<&OsStr> {
+    pub fn extension(&self) -> Option<&str> {
         self.0.extension()
     }
-    pub fn file_stem(&self) -> Option<&OsStr> {
+    pub fn file_stem(&self) -> Option<&str> {
         self.0.file_stem()
     }
     pub fn as_os_str(&self) -> &OsStr {
         self.0.as_os_str()
     }
+    pub fn as_str(&self) -> &str {
+        self.0.as_str()
+    }
     #[deprecated(note = "use Display instead")]
-    pub fn display(&self) -> std::path::Display<'_> {
-        self.0.display()
+    pub fn display(&self) -> ! {
+        unimplemented!()
     }
     #[deprecated(note = "use std::fs::metadata().is_ok() instead")]
-    pub fn exists(&self) -> bool {
-        self.0.exists()
+    pub fn exists(&self) -> ! {
+        unimplemented!()
+    }
+
+    pub fn components(&self) -> Utf8Components<'_> {
+        self.0.components()
     }
     // endregion:delegate-methods
 }
 
 impl fmt::Display for AbsPath {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(&self.0.display(), f)
+        fmt::Display::fmt(&self.0, f)
     }
 }
 
-/// Wrapper around a relative [`PathBuf`].
+/// Wrapper around a relative [`Utf8PathBuf`].
 #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
-pub struct RelPathBuf(PathBuf);
+pub struct RelPathBuf(Utf8PathBuf);
 
-impl From<RelPathBuf> for PathBuf {
-    fn from(RelPathBuf(path_buf): RelPathBuf) -> PathBuf {
+impl From<RelPathBuf> for Utf8PathBuf {
+    fn from(RelPathBuf(path_buf): RelPathBuf) -> Utf8PathBuf {
         path_buf
     }
 }
@@ -257,15 +321,21 @@ impl ops::Deref for RelPathBuf {
     }
 }
 
+impl AsRef<Utf8Path> for RelPathBuf {
+    fn as_ref(&self) -> &Utf8Path {
+        self.0.as_path()
+    }
+}
+
 impl AsRef<Path> for RelPathBuf {
     fn as_ref(&self) -> &Path {
-        self.0.as_path()
+        self.0.as_ref()
     }
 }
 
-impl TryFrom<PathBuf> for RelPathBuf {
-    type Error = PathBuf;
-    fn try_from(path_buf: PathBuf) -> Result<RelPathBuf, PathBuf> {
+impl TryFrom<Utf8PathBuf> for RelPathBuf {
+    type Error = Utf8PathBuf;
+    fn try_from(path_buf: Utf8PathBuf) -> Result<RelPathBuf, Utf8PathBuf> {
         if !path_buf.is_relative() {
             return Err(path_buf);
         }
@@ -274,65 +344,79 @@ impl TryFrom<PathBuf> for RelPathBuf {
 }
 
 impl TryFrom<&str> for RelPathBuf {
-    type Error = PathBuf;
-    fn try_from(path: &str) -> Result<RelPathBuf, PathBuf> {
-        RelPathBuf::try_from(PathBuf::from(path))
+    type Error = Utf8PathBuf;
+    fn try_from(path: &str) -> Result<RelPathBuf, Utf8PathBuf> {
+        RelPathBuf::try_from(Utf8PathBuf::from(path))
     }
 }
 
 impl RelPathBuf {
     /// Coerces to a `RelPath` slice.
     ///
-    /// Equivalent of [`PathBuf::as_path`] for `RelPathBuf`.
+    /// Equivalent of [`Utf8PathBuf::as_path`] for `RelPathBuf`.
     pub fn as_path(&self) -> &RelPath {
         RelPath::new_unchecked(self.0.as_path())
     }
 }
 
-/// Wrapper around a relative [`Path`].
+/// Wrapper around a relative [`Utf8Path`].
 #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
 #[repr(transparent)]
-pub struct RelPath(Path);
+pub struct RelPath(Utf8Path);
+
+impl AsRef<Utf8Path> for RelPath {
+    fn as_ref(&self) -> &Utf8Path {
+        &self.0
+    }
+}
 
 impl AsRef<Path> for RelPath {
     fn as_ref(&self) -> &Path {
-        &self.0
+        self.0.as_ref()
     }
 }
 
 impl RelPath {
     /// Creates a new `RelPath` from `path`, without checking if it is relative.
-    pub fn new_unchecked(path: &Path) -> &RelPath {
-        unsafe { &*(path as *const Path as *const RelPath) }
+    pub fn new_unchecked(path: &Utf8Path) -> &RelPath {
+        unsafe { &*(path as *const Utf8Path as *const RelPath) }
     }
 
-    /// Equivalent of [`Path::to_path_buf`] for `RelPath`.
+    /// Equivalent of [`Utf8Path::to_path_buf`] for `RelPath`.
     pub fn to_path_buf(&self) -> RelPathBuf {
         RelPathBuf::try_from(self.0.to_path_buf()).unwrap()
     }
+
+    pub fn as_utf8_path(&self) -> &Utf8Path {
+        self.as_ref()
+    }
+
+    pub fn as_str(&self) -> &str {
+        self.0.as_str()
+    }
 }
 
 /// Taken from <https://github.com/rust-lang/cargo/blob/79c769c3d7b4c2cf6a93781575b7f592ef974255/src/cargo/util/paths.rs#L60-L85>
-fn normalize_path(path: &Path) -> PathBuf {
+fn normalize_path(path: &Utf8Path) -> Utf8PathBuf {
     let mut components = path.components().peekable();
-    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().copied() {
+    let mut ret = if let Some(c @ Utf8Component::Prefix(..)) = components.peek().copied() {
         components.next();
-        PathBuf::from(c.as_os_str())
+        Utf8PathBuf::from(c.as_str())
     } else {
-        PathBuf::new()
+        Utf8PathBuf::new()
     };
 
     for component in components {
         match component {
-            Component::Prefix(..) => unreachable!(),
-            Component::RootDir => {
-                ret.push(component.as_os_str());
+            Utf8Component::Prefix(..) => unreachable!(),
+            Utf8Component::RootDir => {
+                ret.push(component.as_str());
             }
-            Component::CurDir => {}
-            Component::ParentDir => {
+            Utf8Component::CurDir => {}
+            Utf8Component::ParentDir => {
                 ret.pop();
             }
-            Component::Normal(c) => {
+            Utf8Component::Normal(c) => {
                 ret.push(c);
             }
         }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
index 978ad155609..f30f6a0f23b 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
@@ -23,7 +23,7 @@ snap = "1.1.0"
 indexmap = "2.1.0"
 
 # local deps
-paths.workspace = true
+paths = { workspace = true, features = ["serde1"] }
 tt.workspace = true
 stdx.workspace = true
 text-size.workspace = true
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
index 6b16711a8d8..fd491644648 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
@@ -35,8 +35,11 @@ pub use version::{read_dylib_info, read_version, RustCInfo};
 #[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
 pub enum ProcMacroKind {
     CustomDerive,
-    FuncLike,
     Attr,
+    // This used to be called FuncLike, so that's what the server expects currently.
+    #[serde(alias = "bang")]
+    #[serde(rename(serialize = "FuncLike", deserialize = "FuncLike"))]
+    Bang,
 }
 
 /// A handle to an external process which load dylibs with macros (.so or .dll)
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs
index aa5aff455fd..ad0e1f187b6 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs
@@ -1,11 +1,9 @@
 //! Defines messages for cross-process message passing based on `ndjson` wire protocol
 pub(crate) mod flat;
 
-use std::{
-    io::{self, BufRead, Write},
-    path::PathBuf,
-};
+use std::io::{self, BufRead, Write};
 
+use paths::Utf8PathBuf;
 use serde::{de::DeserializeOwned, Deserialize, Serialize};
 
 use crate::ProcMacroKind;
@@ -27,7 +25,7 @@ pub const CURRENT_API_VERSION: u32 = RUST_ANALYZER_SPAN_SUPPORT;
 #[derive(Debug, Serialize, Deserialize)]
 pub enum Request {
     /// Since [`NO_VERSION_CHECK_VERSION`]
-    ListMacros { dylib_path: PathBuf },
+    ListMacros { dylib_path: Utf8PathBuf },
     /// Since [`NO_VERSION_CHECK_VERSION`]
     ExpandMacro(Box<ExpandMacro>),
     /// Since [`VERSION_CHECK_VERSION`]
@@ -89,7 +87,7 @@ pub struct ExpandMacro {
     /// Possible attributes for the attribute-like macros.
     pub attributes: Option<FlatTree>,
 
-    pub lib: PathBuf,
+    pub lib: Utf8PathBuf,
 
     /// Environment variables to set during macro expansion.
     pub env: Vec<(String, String)>,
@@ -273,7 +271,7 @@ mod tests {
             macro_body: FlatTree::new(&tt, CURRENT_API_VERSION, &mut span_data_table),
             macro_name: Default::default(),
             attributes: None,
-            lib: std::env::current_dir().unwrap(),
+            lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(),
             env: Default::default(),
             current_dir: Default::default(),
             has_global_spans: ExpnGlobals {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
index caf9e237fdd..99cdbd930e1 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
@@ -88,8 +88,6 @@ impl std::fmt::Debug for TokenId {
     }
 }
 
-impl tt::Span for TokenId {}
-
 #[derive(Serialize, Deserialize, Debug)]
 pub struct FlatTree {
     subtree: Vec<u32>,
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
index 72f95643c8b..35d48a15543 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
@@ -175,7 +175,7 @@ fn mk_child(
     env: &FxHashMap<String, String>,
     null_stderr: bool,
 ) -> io::Result<Child> {
-    let mut cmd = Command::new(path.as_os_str());
+    let mut cmd = Command::new(path);
     cmd.envs(env)
         .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
         .stdin(Stdio::piped())
@@ -183,7 +183,7 @@ fn mk_child(
         .stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() });
     if cfg!(windows) {
         let mut path_var = std::ffi::OsString::new();
-        path_var.push(path.parent().unwrap().parent().unwrap().as_os_str());
+        path_var.push(path.parent().unwrap().parent().unwrap());
         path_var.push("\\bin;");
         path_var.push(std::env::var_os("PATH").unwrap_or_default());
         cmd.env("PATH", path_var);
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
index 52b4cced5f5..22c34ff1678 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
@@ -1,16 +1,11 @@
 //! Handles dynamic library loading for proc macro
 
-use std::{
-    fmt,
-    fs::File,
-    io,
-    path::{Path, PathBuf},
-};
+use std::{fmt, fs::File, io};
 
 use libloading::Library;
 use memmap2::Mmap;
 use object::Object;
-use paths::AbsPath;
+use paths::{AbsPath, Utf8Path, Utf8PathBuf};
 use proc_macro::bridge;
 use proc_macro_api::{read_dylib_info, ProcMacroKind};
 
@@ -26,7 +21,7 @@ fn is_derive_registrar_symbol(symbol: &str) -> bool {
     symbol.contains(NEW_REGISTRAR_SYMBOL)
 }
 
-fn find_registrar_symbol(file: &Path) -> io::Result<Option<String>> {
+fn find_registrar_symbol(file: &Utf8Path) -> io::Result<Option<String>> {
     let file = File::open(file)?;
     let buffer = unsafe { Mmap::map(&file)? };
 
@@ -62,12 +57,12 @@ fn find_registrar_symbol(file: &Path) -> io::Result<Option<String>> {
 ///
 /// It seems that on Windows that behaviour is default, so we do nothing in that case.
 #[cfg(windows)]
-fn load_library(file: &Path) -> Result<Library, libloading::Error> {
+fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
     unsafe { Library::new(file) }
 }
 
 #[cfg(unix)]
-fn load_library(file: &Path) -> Result<Library, libloading::Error> {
+fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
     use libloading::os::unix::Library as UnixLibrary;
     use std::os::raw::c_int;
 
@@ -116,14 +111,14 @@ struct ProcMacroLibraryLibloading {
 }
 
 impl ProcMacroLibraryLibloading {
-    fn open(file: &Path) -> Result<Self, LoadProcMacroDylibError> {
+    fn open(file: &Utf8Path) -> Result<Self, LoadProcMacroDylibError> {
         let symbol_name = find_registrar_symbol(file)?.ok_or_else(|| {
-            invalid_data_err(format!("Cannot find registrar symbol in file {}", file.display()))
+            invalid_data_err(format!("Cannot find registrar symbol in file {file}"))
         })?;
 
-        let abs_file: &AbsPath = file.try_into().map_err(|_| {
-            invalid_data_err(format!("expected an absolute path, got {}", file.display()))
-        })?;
+        let abs_file: &AbsPath = file
+            .try_into()
+            .map_err(|_| invalid_data_err(format!("expected an absolute path, got {file}")))?;
         let version_info = read_dylib_info(abs_file)?;
 
         let lib = load_library(file).map_err(invalid_data_err)?;
@@ -138,10 +133,10 @@ pub struct Expander {
 }
 
 impl Expander {
-    pub fn new(lib: &Path) -> Result<Expander, LoadProcMacroDylibError> {
+    pub fn new(lib: &Utf8Path) -> Result<Expander, LoadProcMacroDylibError> {
         // Some libraries for dynamic loading require canonicalized path even when it is
         // already absolute
-        let lib = lib.canonicalize()?;
+        let lib = lib.canonicalize_utf8()?;
 
         let lib = ensure_file_with_lock_free_access(&lib)?;
 
@@ -176,30 +171,26 @@ impl Expander {
 
 /// Copy the dylib to temp directory to prevent locking in Windows
 #[cfg(windows)]
-fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
+fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result<Utf8PathBuf> {
     use std::collections::hash_map::RandomState;
-    use std::ffi::OsString;
     use std::hash::{BuildHasher, Hasher};
 
     if std::env::var("RA_DONT_COPY_PROC_MACRO_DLL").is_ok() {
         return Ok(path.to_path_buf());
     }
 
-    let mut to = std::env::temp_dir();
+    let mut to = Utf8PathBuf::from_path_buf(std::env::temp_dir()).unwrap();
 
     let file_name = path.file_name().ok_or_else(|| {
-        io::Error::new(
-            io::ErrorKind::InvalidInput,
-            format!("File path is invalid: {}", path.display()),
-        )
+        io::Error::new(io::ErrorKind::InvalidInput, format!("File path is invalid: {path}"))
     })?;
 
     // Generate a unique number by abusing `HashMap`'s hasher.
     // Maybe this will also "inspire" a libs team member to finally put `rand` in libstd.
     let t = RandomState::new().build_hasher().finish();
 
-    let mut unique_name = OsString::from(t.to_string());
-    unique_name.push(file_name);
+    let mut unique_name = t.to_string();
+    unique_name.push_str(file_name);
 
     to.push(unique_name);
     std::fs::copy(path, &to).unwrap();
@@ -207,6 +198,6 @@ fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
 }
 
 #[cfg(unix)]
-fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
-    Ok(path.to_path_buf())
+fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result<Utf8PathBuf> {
+    Ok(path.to_owned())
 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
index 831632c64c0..2472c1e3119 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
@@ -33,12 +33,11 @@ use std::{
     collections::{hash_map::Entry, HashMap},
     env,
     ffi::OsString,
-    fs,
-    path::{Path, PathBuf},
-    thread,
+    fs, thread,
     time::SystemTime,
 };
 
+use paths::{Utf8Path, Utf8PathBuf};
 use proc_macro_api::{
     msg::{
         self, deserialize_span_data_index_map, serialize_span_data_index_map, ExpnGlobals,
@@ -53,7 +52,7 @@ use crate::server::TokenStream;
 // see `build.rs`
 include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
 
-trait ProcMacroSrvSpan: tt::Span {
+trait ProcMacroSrvSpan: Copy {
     type Server: proc_macro::bridge::server::Server<TokenStream = TokenStream<Self>>;
     fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server;
 }
@@ -81,7 +80,7 @@ impl ProcMacroSrvSpan for Span {
 
 #[derive(Default)]
 pub struct ProcMacroSrv {
-    expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>,
+    expanders: HashMap<(Utf8PathBuf, SystemTime), dylib::Expander>,
     span_mode: SpanMode,
 }
 
@@ -149,23 +148,22 @@ impl ProcMacroSrv {
 
     pub fn list_macros(
         &mut self,
-        dylib_path: &Path,
+        dylib_path: &Utf8Path,
     ) -> Result<Vec<(String, ProcMacroKind)>, String> {
         let expander = self.expander(dylib_path)?;
         Ok(expander.list_macros())
     }
 
-    fn expander(&mut self, path: &Path) -> Result<&dylib::Expander, String> {
+    fn expander(&mut self, path: &Utf8Path) -> Result<&dylib::Expander, String> {
         let time = fs::metadata(path)
             .and_then(|it| it.modified())
-            .map_err(|err| format!("Failed to get file metadata for {}: {err}", path.display()))?;
+            .map_err(|err| format!("Failed to get file metadata for {path}: {err}",))?;
 
         Ok(match self.expanders.entry((path.to_path_buf(), time)) {
-            Entry::Vacant(v) => {
-                v.insert(dylib::Expander::new(path).map_err(|err| {
-                    format!("Cannot create expander for {}: {err}", path.display())
-                })?)
-            }
+            Entry::Vacant(v) => v.insert(
+                dylib::Expander::new(path)
+                    .map_err(|err| format!("Cannot create expander for {path}: {err}",))?,
+            ),
             Entry::Occupied(e) => e.into_mut(),
         })
     }
@@ -306,6 +304,6 @@ impl Drop for EnvSnapshot {
 mod tests;
 
 #[cfg(test)]
-pub fn proc_macro_test_dylib_path() -> std::path::PathBuf {
+pub fn proc_macro_test_dylib_path() -> paths::Utf8PathBuf {
     proc_macro_test::PROC_MACRO_TEST_LOCATION.into()
 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs
index 686d5b0438a..631fd84aa24 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs
@@ -108,7 +108,7 @@ impl ProcMacros {
                     (trait_name.to_string(), ProcMacroKind::CustomDerive)
                 }
                 bridge::client::ProcMacro::Bang { name, .. } => {
-                    (name.to_string(), ProcMacroKind::FuncLike)
+                    (name.to_string(), ProcMacroKind::Bang)
                 }
                 bridge::client::ProcMacro::Attr { name, .. } => {
                     (name.to_string(), ProcMacroKind::Attr)
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs
index 408db60e872..b1a448427c6 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs
@@ -101,6 +101,8 @@ pub(super) struct TokenStreamBuilder<S> {
 /// pub(super)lic implementation details for the `TokenStream` type, such as iterators.
 pub(super) mod token_stream {
 
+    use core::fmt;
+
     use super::{TokenStream, TokenTree};
 
     /// An iterator over `TokenStream`'s `TokenTree`s.
@@ -122,7 +124,7 @@ pub(super) mod token_stream {
     ///
     /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to
     /// change these errors into `LexError`s later.
-    impl<S: tt::Span> TokenStream<S> {
+    impl<S: Copy + fmt::Debug> TokenStream<S> {
         pub(crate) fn from_str(src: &str, call_site: S) -> Result<TokenStream<S>, String> {
             let subtree =
                 mbe::parse_to_token_tree_static_span(call_site, src).ok_or("lexing error")?;
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
index 11b008fc0b4..63342825380 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
@@ -254,14 +254,14 @@ fn list_test_macros() {
     let res = list().join("\n");
 
     expect![[r#"
-        fn_like_noop [FuncLike]
-        fn_like_panic [FuncLike]
-        fn_like_error [FuncLike]
-        fn_like_clone_tokens [FuncLike]
-        fn_like_mk_literals [FuncLike]
-        fn_like_mk_idents [FuncLike]
-        fn_like_span_join [FuncLike]
-        fn_like_span_ops [FuncLike]
+        fn_like_noop [Bang]
+        fn_like_panic [Bang]
+        fn_like_error [Bang]
+        fn_like_clone_tokens [Bang]
+        fn_like_mk_literals [Bang]
+        fn_like_mk_idents [Bang]
+        fn_like_span_join [Bang]
+        fn_like_span_ops [Bang]
         attr_noop [Attr]
         attr_panic [Attr]
         attr_error [Attr]
diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
index 924a4a89e21..097ee1f75cd 100644
--- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
@@ -25,8 +25,9 @@ itertools.workspace = true
 
 # local deps
 base-db.workspace = true
+span.workspace = true
 cfg.workspace = true
-paths.workspace = true
+paths = { workspace = true, features = ["serde1"] }
 stdx.workspace = true
 toolchain.workspace = true
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
index 709fc037174..d40eb26063d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
@@ -77,7 +77,7 @@ impl WorkspaceBuildScripts {
                 cmd.args(&config.extra_args);
 
                 cmd.arg("--manifest-path");
-                cmd.arg(workspace_root.join("Cargo.toml").as_os_str());
+                cmd.arg(workspace_root.join("Cargo.toml"));
 
                 if let Some(target_dir) = &config.target_dir {
                     cmd.arg("--target-dir").arg(target_dir);
@@ -354,16 +354,11 @@ impl WorkspaceBuildScripts {
                             }
                             // cargo_metadata crate returns default (empty) path for
                             // older cargos, which is not absolute, so work around that.
-                            let out_dir = mem::take(&mut message.out_dir).into_os_string();
-                            if !out_dir.is_empty() {
-                                let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir));
+                            let out_dir = mem::take(&mut message.out_dir);
+                            if !out_dir.as_str().is_empty() {
+                                let out_dir = AbsPathBuf::assert(out_dir);
                                 // inject_cargo_env(package, package_build_data);
-                                // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
-                                if let Some(out_dir) =
-                                    out_dir.as_os_str().to_str().map(|s| s.to_owned())
-                                {
-                                    data.envs.push(("OUT_DIR".to_owned(), out_dir));
-                                }
+                                data.envs.push(("OUT_DIR".to_owned(), out_dir.as_str().to_owned()));
                                 data.out_dir = Some(out_dir);
                                 data.cfgs = cfgs;
                             }
@@ -377,8 +372,8 @@ impl WorkspaceBuildScripts {
                                 if let Some(filename) =
                                     message.filenames.iter().find(|name| is_dylib(name))
                                 {
-                                    let filename = AbsPathBuf::assert(PathBuf::from(&filename));
-                                    data.proc_macro_dylib_path = Some(filename);
+                                    let filename = AbsPath::assert(filename);
+                                    data.proc_macro_dylib_path = Some(filename.to_owned());
                                 }
                             }
                         });
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 53b41ea1e87..51c1b094f7b 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
@@ -1,17 +1,16 @@
 //! See [`CargoWorkspace`].
 
 use std::ops;
-use std::path::PathBuf;
 use std::str::from_utf8;
 
 use anyhow::Context;
-use base_db::Edition;
 use cargo_metadata::{CargoOpt, MetadataCommand};
 use la_arena::{Arena, Idx};
-use paths::{AbsPath, AbsPathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use serde::Deserialize;
 use serde_json::from_value;
+use span::Edition;
 use toolchain::Tool;
 
 use crate::{utf8_stdout, InvocationLocation, ManifestPath, Sysroot};
@@ -100,7 +99,7 @@ pub struct CargoConfig {
     pub invocation_strategy: InvocationStrategy,
     pub invocation_location: InvocationLocation,
     /// Optional path to use instead of `target` when building
-    pub target_dir: Option<PathBuf>,
+    pub target_dir: Option<Utf8PathBuf>,
 }
 
 pub type Package = Idx<PackageData>;
@@ -262,7 +261,7 @@ impl CargoWorkspace {
                 }
             }
         }
-        meta.current_dir(current_dir.as_os_str());
+        meta.current_dir(current_dir);
 
         let mut other_options = vec![];
         // cargo metadata only supports a subset of flags of what cargo usually accepts, and usually
@@ -351,7 +350,7 @@ impl CargoWorkspace {
                 id: id.repr.clone(),
                 name,
                 version,
-                manifest: AbsPathBuf::assert(manifest_path.into()).try_into().unwrap(),
+                manifest: AbsPathBuf::assert(manifest_path).try_into().unwrap(),
                 targets: Vec::new(),
                 is_local,
                 is_member,
@@ -370,7 +369,7 @@ impl CargoWorkspace {
                 let tgt = targets.alloc(TargetData {
                     package: pkg,
                     name,
-                    root: AbsPathBuf::assert(src_path.into()),
+                    root: AbsPathBuf::assert(src_path),
                     kind: TargetKind::new(&kind),
                     required_features,
                 });
@@ -393,11 +392,9 @@ impl CargoWorkspace {
             packages[source].active_features.extend(node.features);
         }
 
-        let workspace_root =
-            AbsPathBuf::assert(PathBuf::from(meta.workspace_root.into_os_string()));
+        let workspace_root = AbsPathBuf::assert(meta.workspace_root);
 
-        let target_directory =
-            AbsPathBuf::assert(PathBuf::from(meta.target_directory.into_os_string()));
+        let target_directory = AbsPathBuf::assert(meta.target_directory);
 
         CargoWorkspace { packages, targets, workspace_root, target_directory }
     }
@@ -409,7 +406,7 @@ impl CargoWorkspace {
     pub fn target_by_root(&self, root: &AbsPath) -> Option<Target> {
         self.packages()
             .filter(|&pkg| self[pkg].is_member)
-            .find_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
+            .find_map(|pkg| self[pkg].targets.iter().find(|&&it| self[it].root == root))
             .copied()
     }
 
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 5b91f5d8058..28696aa3277 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -127,8 +127,8 @@ impl ProjectManifest {
                 .filter_map(Result::ok)
                 .map(|it| it.path().join("Cargo.toml"))
                 .filter(|it| it.exists())
-                .map(AbsPathBuf::assert)
-                .filter_map(|it| it.try_into().ok())
+                .map(AbsPathBuf::try_from)
+                .filter_map(|it| it.ok()?.try_into().ok())
                 .collect()
         }
     }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
index fba0aaa8ce9..512588cc8f8 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
@@ -49,12 +49,12 @@
 //! user explores them belongs to that extension (it's totally valid to change
 //! rust-project.json over time via configuration request!)
 
-use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition};
+use base_db::{CrateDisplayName, CrateId, CrateName, Dependency};
 use la_arena::RawIdx;
-use paths::{AbsPath, AbsPathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
 use rustc_hash::FxHashMap;
 use serde::{de, Deserialize};
-use std::path::PathBuf;
+use span::Edition;
 
 use crate::cfg_flag::CfgFlag;
 
@@ -113,7 +113,7 @@ impl ProjectJson {
                         .unwrap_or_else(|| root_module.starts_with(base));
                     let (include, exclude) = match crate_data.source {
                         Some(src) => {
-                            let absolutize = |dirs: Vec<PathBuf>| {
+                            let absolutize = |dirs: Vec<Utf8PathBuf>| {
                                 dirs.into_iter().map(absolutize_on_base).collect::<Vec<_>>()
                             };
                             (absolutize(src.include_dirs), absolutize(src.exclude_dirs))
@@ -176,15 +176,15 @@ impl ProjectJson {
 
 #[derive(Deserialize, Debug, Clone)]
 pub struct ProjectJsonData {
-    sysroot: Option<PathBuf>,
-    sysroot_src: Option<PathBuf>,
+    sysroot: Option<Utf8PathBuf>,
+    sysroot_src: Option<Utf8PathBuf>,
     crates: Vec<CrateData>,
 }
 
 #[derive(Deserialize, Debug, Clone)]
 struct CrateData {
     display_name: Option<String>,
-    root_module: PathBuf,
+    root_module: Utf8PathBuf,
     edition: EditionData,
     #[serde(default)]
     version: Option<semver::Version>,
@@ -194,7 +194,7 @@ struct CrateData {
     target: Option<String>,
     #[serde(default)]
     env: FxHashMap<String, String>,
-    proc_macro_dylib_path: Option<PathBuf>,
+    proc_macro_dylib_path: Option<Utf8PathBuf>,
     is_workspace_member: Option<bool>,
     source: Option<CrateSource>,
     #[serde(default)]
@@ -238,8 +238,8 @@ struct DepData {
 
 #[derive(Deserialize, Debug, Clone)]
 struct CrateSource {
-    include_dirs: Vec<PathBuf>,
-    exclude_dirs: Vec<PathBuf>,
+    include_dirs: Vec<Utf8PathBuf>,
+    exclude_dirs: Vec<Utf8PathBuf>,
 }
 
 fn deserialize_crate_name<'de, D>(de: D) -> std::result::Result<CrateName, D::Error>
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 3127bae8b0c..1142d6243d2 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -4,13 +4,13 @@
 //! but we can't process `.rlib` and need source code instead. The source code
 //! is typically installed with `rustup component add rust-src` command.
 
-use std::{env, fs, iter, ops, path::PathBuf, process::Command, sync::Arc};
+use std::{env, fs, iter, ops, process::Command, sync::Arc};
 
 use anyhow::{format_err, Result};
 use base_db::CrateName;
 use itertools::Itertools;
 use la_arena::{Arena, Idx};
-use paths::{AbsPath, AbsPathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
 use rustc_hash::FxHashMap;
 use toolchain::{probe_for_binary, Tool};
 
@@ -419,7 +419,7 @@ fn discover_sysroot_dir(
     rustc.current_dir(current_dir).args(["--print", "sysroot"]);
     tracing::debug!("Discovering sysroot by {:?}", rustc);
     let stdout = utf8_stdout(rustc)?;
-    Ok(AbsPathBuf::assert(PathBuf::from(stdout)))
+    Ok(AbsPathBuf::assert(Utf8PathBuf::from(stdout)))
 }
 
 fn discover_sysroot_src_dir(sysroot_path: &AbsPathBuf) -> Option<AbsPathBuf> {
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 b9b1b701f6d..fc0b507b332 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -1,12 +1,9 @@
-use std::{
-    ops::Deref,
-    path::{Path, PathBuf},
-};
+use std::ops::Deref;
 
 use base_db::{CrateGraph, FileId, ProcMacroPaths};
 use cfg::{CfgAtom, CfgDiff};
 use expect_test::{expect_file, ExpectFile};
-use paths::{AbsPath, AbsPathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
 use rustc_hash::FxHashMap;
 use serde::de::DeserializeOwned;
 use triomphe::Arc;
@@ -113,17 +110,16 @@ fn replace_root(s: &mut String, direction: bool) {
 fn replace_fake_sys_root(s: &mut String) {
     let fake_sysroot_path = get_test_path("fake-sysroot");
     let fake_sysroot_path = if cfg!(windows) {
-        let normalized_path =
-            fake_sysroot_path.to_str().expect("expected str").replace('\\', r#"\\"#);
+        let normalized_path = fake_sysroot_path.as_str().replace('\\', r#"\\"#);
         format!(r#"{}\\"#, normalized_path)
     } else {
-        format!("{}/", fake_sysroot_path.to_str().expect("expected str"))
+        format!("{}/", fake_sysroot_path.as_str())
     };
     *s = s.replace(&fake_sysroot_path, "$FAKESYSROOT$")
 }
 
-fn get_test_path(file: &str) -> PathBuf {
-    let base = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+fn get_test_path(file: &str) -> Utf8PathBuf {
+    let base = Utf8PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     base.join("test_data").join(file)
 }
 
@@ -139,7 +135,7 @@ fn get_fake_sysroot() -> Sysroot {
 fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
     let mut root = "$ROOT$".to_owned();
     replace_root(&mut root, true);
-    let path = Path::new(&root);
+    let path = Utf8Path::new(&root);
     let base = AbsPath::assert(path);
     ProjectJson::new(base, data)
 }
@@ -268,7 +264,7 @@ fn smoke_test_real_sysroot_cargo() {
 
     let cargo_workspace = CargoWorkspace::new(meta);
     let sysroot = Ok(Sysroot::discover(
-        AbsPath::assert(Path::new(env!("CARGO_MANIFEST_DIR"))),
+        AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
         &Default::default(),
         true,
     )
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 1a138b17bad..b8c5885108d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -6,13 +6,14 @@ use std::{collections::VecDeque, fmt, fs, iter, str::FromStr, sync};
 
 use anyhow::{format_err, Context};
 use base_db::{
-    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
-    FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult,
+    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, FileId,
+    LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult,
 };
 use cfg::{CfgAtom, CfgDiff, CfgOptions};
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
+use span::Edition;
 use stdx::always;
 use toolchain::Tool;
 use triomphe::Arc;
@@ -718,19 +719,22 @@ impl ProjectWorkspace {
     ) -> (CrateGraph, ProcMacroPaths) {
         let _p = tracing::span!(tracing::Level::INFO, "ProjectWorkspace::to_crate_graph").entered();
 
-        let (mut crate_graph, proc_macros) = match self {
+        let ((mut crate_graph, proc_macros), sysroot) = match self {
             ProjectWorkspace::Json {
                 project,
                 sysroot,
                 rustc_cfg,
                 toolchain: _,
                 target_layout: _,
-            } => project_json_to_crate_graph(
-                rustc_cfg.clone(),
-                load,
-                project,
-                sysroot.as_ref().ok(),
-                extra_env,
+            } => (
+                project_json_to_crate_graph(
+                    rustc_cfg.clone(),
+                    load,
+                    project,
+                    sysroot.as_ref().ok(),
+                    extra_env,
+                ),
+                sysroot,
             ),
             ProjectWorkspace::Cargo {
                 cargo,
@@ -742,14 +746,17 @@ impl ProjectWorkspace {
                 toolchain: _,
                 target_layout: _,
                 cargo_config_extra_env: _,
-            } => cargo_to_crate_graph(
-                load,
-                rustc.as_ref().map(|a| a.as_ref()).ok(),
-                cargo,
-                sysroot.as_ref().ok(),
-                rustc_cfg.clone(),
-                cfg_overrides,
-                build_scripts,
+            } => (
+                cargo_to_crate_graph(
+                    load,
+                    rustc.as_ref().map(|a| a.as_ref()).ok(),
+                    cargo,
+                    sysroot.as_ref().ok(),
+                    rustc_cfg.clone(),
+                    cfg_overrides,
+                    build_scripts,
+                ),
+                sysroot,
             ),
             ProjectWorkspace::DetachedFiles {
                 files,
@@ -757,11 +764,20 @@ impl ProjectWorkspace {
                 rustc_cfg,
                 toolchain: _,
                 target_layout: _,
-            } => {
-                detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot.as_ref().ok())
-            }
+            } => (
+                detached_files_to_crate_graph(
+                    rustc_cfg.clone(),
+                    load,
+                    files,
+                    sysroot.as_ref().ok(),
+                ),
+                sysroot,
+            ),
         };
-        if crate_graph.patch_cfg_if() {
+
+        if matches!(sysroot.as_ref().map(|it| it.mode()), Ok(SysrootMode::Workspace(_)))
+            && crate_graph.patch_cfg_if()
+        {
             tracing::debug!("Patched std to depend on cfg-if")
         } else {
             tracing::debug!("Did not patch std to depend on cfg-if")
@@ -1077,6 +1093,8 @@ fn cargo_to_crate_graph(
         }
     }
 
+    let mut delayed_dev_deps = vec![];
+
     // Now add a dep edge from all targets of upstream to the lib
     // target of downstream.
     for pkg in cargo.packages() {
@@ -1091,11 +1109,31 @@ fn cargo_to_crate_graph(
                     continue;
                 }
 
+                // If the dependency is a dev-dependency with both crates being member libraries of
+                // the workspace we delay adding the edge. The reason can be read up on in
+                // https://github.com/rust-lang/rust-analyzer/issues/14167
+                // but in short, such an edge is able to cause some form of cycle in the crate graph
+                // for normal dependencies. If we do run into a cycle like this, we want to prefer
+                // the non dev-dependency edge, and so the easiest way to do that is by adding the
+                // dev-dependency edges last.
+                if dep.kind == DepKind::Dev
+                    && matches!(kind, TargetKind::Lib { .. })
+                    && cargo[dep.pkg].is_member
+                    && cargo[pkg].is_member
+                {
+                    delayed_dev_deps.push((from, name.clone(), to));
+                    continue;
+                }
+
                 add_dep(crate_graph, from, name.clone(), to)
             }
         }
     }
 
+    for (from, name, to) in delayed_dev_deps {
+        add_dep(crate_graph, from, name, to);
+    }
+
     if has_private {
         // If the user provided a path to rustc sources, we add all the rustc_private crates
         // and create dependencies on them for the crates which opt-in to that
@@ -1151,7 +1189,6 @@ fn detached_files_to_crate_graph(
         };
         let display_name = detached_file
             .file_stem()
-            .and_then(|os_str| os_str.to_str())
             .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_owned()));
         let detached_file_crate = crate_graph.add_crate_root(
             file_id,
@@ -1228,6 +1265,7 @@ fn handle_rustc_crates(
                 let kind @ TargetKind::Lib { is_proc_macro } = rustc_workspace[tgt].kind else {
                     continue;
                 };
+                let pkg_crates = &mut rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new);
                 if let Some(file_id) = load(&rustc_workspace[tgt].root) {
                     let crate_id = add_target_crate_root(
                         crate_graph,
@@ -1246,7 +1284,7 @@ fn handle_rustc_crates(
                     if let Some(proc_macro) = libproc_macro {
                         add_proc_macro_dep(crate_graph, crate_id, proc_macro, is_proc_macro);
                     }
-                    rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
+                    pkg_crates.push(crate_id);
                 }
             }
         }
@@ -1533,7 +1571,7 @@ fn inject_cargo_env(package: &PackageData, env: &mut Env) {
     // CARGO_BIN_NAME, CARGO_BIN_EXE_<name>
 
     let manifest_dir = package.manifest.parent();
-    env.set("CARGO_MANIFEST_DIR", manifest_dir.as_os_str().to_string_lossy().into_owned());
+    env.set("CARGO_MANIFEST_DIR", manifest_dir.as_str().to_owned());
 
     // Not always right, but works for common cases.
     env.set("CARGO", "cargo".into());
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index e6984d6f41b..6d70124188d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -43,6 +43,7 @@ nohash-hasher.workspace = true
 always-assert = "0.2.0"
 walkdir = "2.3.2"
 semver.workspace = true
+memchr = "2.7.1"
 
 cfg.workspace = true
 flycheck.workspace = true
@@ -63,7 +64,7 @@ parser.workspace = true
 toolchain.workspace = true
 vfs-notify.workspace = true
 vfs.workspace = true
-memchr = "2.7.1"
+paths.workspace = true
 
 [target.'cfg(windows)'.dependencies]
 winapi = "0.3.9"
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
index e747ec87b1c..78920f3abac 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
@@ -190,7 +190,7 @@ fn run_server() -> anyhow::Result<()> {
         Some(it) => it,
         None => {
             let cwd = env::current_dir()?;
-            AbsPathBuf::assert(cwd)
+            AbsPathBuf::assert_utf8(cwd)
         }
     };
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 5c474908e7a..fdd77199aa0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -70,7 +70,7 @@ impl flags::AnalysisStats {
 
         let mut db_load_sw = self.stop_watch();
 
-        let path = AbsPathBuf::assert(env::current_dir()?.join(&self.path));
+        let path = AbsPathBuf::assert_utf8(env::current_dir()?.join(&self.path));
         let manifest = ProjectManifest::discover_single(&path)?;
 
         let mut workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
@@ -279,7 +279,8 @@ impl flags::AnalysisStats {
         let mut all = 0;
         let mut fail = 0;
         for &a in adts {
-            if db.generic_params(a.into()).iter().next().is_some() {
+            let generic_params = db.generic_params(a.into());
+            if generic_params.iter().next().is_some() || generic_params.iter_lt().next().is_some() {
                 // Data types with generics don't have layout.
                 continue;
             }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
index bd2646126dc..79d6226debf 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -16,7 +16,7 @@ impl flags::Diagnostics {
         let cargo_config =
             CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() };
         let with_proc_macro_server = if let Some(p) = &self.proc_macro_srv {
-            let path = vfs::AbsPathBuf::assert(std::env::current_dir()?.join(p));
+            let path = vfs::AbsPathBuf::assert_utf8(std::env::current_dir()?.join(p));
             ProcMacroServerChoice::Explicit(path)
         } else {
             ProcMacroServerChoice::Sysroot
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
index 3f68c5d053b..b3b8ab9a404 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
@@ -235,6 +235,7 @@ pub struct RunTests {
 #[derive(Debug)]
 pub struct RustcTests {
     pub rustc_repo: PathBuf,
+
     pub filter: Option<String>,
 }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
index f3f5ec1ebde..3ff9be7102f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
@@ -283,7 +283,7 @@ impl flags::Lsif {
             with_proc_macro_server: ProcMacroServerChoice::Sysroot,
             prefill_caches: false,
         };
-        let path = AbsPathBuf::assert(env::current_dir()?.join(self.path));
+        let path = AbsPathBuf::assert_utf8(env::current_dir()?.join(self.path));
         let manifest = ProjectManifest::discover_single(&path)?;
 
         let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
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 84f2e600874..eeec13a14be 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
@@ -76,7 +76,7 @@ impl Tester {
         );
 
         let workspace = ProjectWorkspace::DetachedFiles {
-            files: vec![tmp_file.clone()],
+            files: vec![tmp_file],
             sysroot,
             rustc_cfg: vec![],
             toolchain: None,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index 1061a433a58..aef2c1be224 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -27,7 +27,8 @@ impl flags::Scip {
             with_proc_macro_server: ProcMacroServerChoice::Sysroot,
             prefill_caches: true,
         };
-        let root = vfs::AbsPathBuf::assert(std::env::current_dir()?.join(&self.path)).normalize();
+        let root =
+            vfs::AbsPathBuf::assert_utf8(std::env::current_dir()?.join(&self.path)).normalize();
 
         let mut config = crate::config::Config::new(
             root.clone(),
@@ -63,12 +64,7 @@ impl flags::Scip {
                 special_fields: Default::default(),
             })
             .into(),
-            project_root: format!(
-                "file://{}",
-                root.as_os_str()
-                    .to_str()
-                    .ok_or(anyhow::format_err!("Unable to normalize project_root path"))?
-            ),
+            project_root: format!("file://{root}"),
             text_document_encoding: scip_types::TextEncoding::UTF8.into(),
             special_fields: Default::default(),
         };
@@ -216,7 +212,7 @@ fn get_relative_filepath(
     rootpath: &vfs::AbsPathBuf,
     file_id: ide::FileId,
 ) -> Option<String> {
-    Some(vfs.file_path(file_id).as_path()?.strip_prefix(rootpath)?.as_ref().to_str()?.to_owned())
+    Some(vfs.file_path(file_id).as_path()?.strip_prefix(rootpath)?.as_str().to_owned())
 }
 
 // SCIP Ranges have a (very large) optimization that ranges if they are on the same line
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 cbf15246590..7475a8e6e6d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -7,11 +7,7 @@
 //! configure the server itself, feature flags are passed into analysis, and
 //! tweak things like automatic insertion of `()` in completions.
 
-use std::{
-    fmt, iter,
-    ops::Not,
-    path::{Path, PathBuf},
-};
+use std::{fmt, iter, ops::Not};
 
 use cfg::{CfgAtom, CfgDiff};
 use flycheck::FlycheckConfig;
@@ -27,6 +23,7 @@ use ide_db::{
 };
 use itertools::Itertools;
 use lsp_types::{ClientCapabilities, MarkupKind};
+use paths::{Utf8Path, Utf8PathBuf};
 use project_model::{
     CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustLibSource,
 };
@@ -327,7 +324,7 @@ config_data! {
         /// These 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<PathBuf> = "[]",
+        files_excludeDirs: Vec<Utf8PathBuf> = "[]",
         /// Controls file watching implementation.
         files_watcher: FilesWatcherDef = "\"client\"",
 
@@ -378,6 +375,8 @@ config_data! {
         /// How to render the size information in a memory layout hover.
         hover_memoryLayout_size: Option<MemoryLayoutHoverRenderKindDef> = "\"both\"",
 
+        /// How many fields of a struct to display when hovering a struct.
+        hover_show_structFields: Option<usize> = "null",
         /// How many associated items of a trait to display when hovering a trait.
         hover_show_traitAssocItems: Option<usize> = "null",
 
@@ -516,7 +515,7 @@ config_data! {
         /// This config takes a map of crate names with the exported proc-macro names to ignore as values.
         procMacro_ignored: FxHashMap<Box<str>, Box<[Box<str>]>>          = "{}",
         /// Internal config, path to proc-macro server executable.
-        procMacro_server: Option<PathBuf>          = "null",
+        procMacro_server: Option<Utf8PathBuf>          = "null",
 
         /// Exclude imports from find-all-references.
         references_excludeImports: bool = "false",
@@ -864,7 +863,7 @@ impl Config {
         }
         let mut errors = Vec::new();
         self.detached_files =
-            get_field::<Vec<PathBuf>>(&mut json, &mut errors, "detachedFiles", None, "[]")
+            get_field::<Vec<Utf8PathBuf>>(&mut json, &mut errors, "detachedFiles", None, "[]")
                 .into_iter()
                 .map(AbsPathBuf::assert)
                 .collect();
@@ -956,7 +955,7 @@ impl Config {
     pub fn has_linked_projects(&self) -> bool {
         !self.data.linkedProjects.is_empty()
     }
-    pub fn linked_manifests(&self) -> impl Iterator<Item = &Path> + '_ {
+    pub fn linked_manifests(&self) -> impl Iterator<Item = &Utf8Path> + '_ {
         self.data.linkedProjects.iter().filter_map(|it| match it {
             ManifestOrProjectJson::Manifest(p) => Some(&**p),
             ManifestOrProjectJson::ProjectJson(_) => None,
@@ -1014,6 +1013,17 @@ impl Config {
         )
     }
 
+    pub fn did_change_watched_files_relative_pattern_support(&self) -> bool {
+        try_or_def!(
+            self.caps
+                .workspace
+                .as_ref()?
+                .did_change_watched_files
+                .as_ref()?
+                .relative_pattern_support?
+        )
+    }
+
     pub fn prefill_caches(&self) -> bool {
         self.data.cachePriming_enable
     }
@@ -1410,9 +1420,11 @@ impl Config {
         }
     }
 
-    fn target_dir_from_config(&self) -> Option<PathBuf> {
+    fn target_dir_from_config(&self) -> Option<Utf8PathBuf> {
         self.data.cargo_targetDir.as_ref().and_then(|target_dir| match target_dir {
-            TargetDirectory::UseSubdirectory(true) => Some(PathBuf::from("target/rust-analyzer")),
+            TargetDirectory::UseSubdirectory(true) => {
+                Some(Utf8PathBuf::from("target/rust-analyzer"))
+            }
             TargetDirectory::UseSubdirectory(false) => None,
             TargetDirectory::Directory(dir) if dir.is_relative() => Some(dir.clone()),
             TargetDirectory::Directory(_) => None,
@@ -1691,6 +1703,7 @@ impl Config {
             },
             keywords: self.data.hover_documentation_keywords_enable,
             max_trait_assoc_items_count: self.data.hover_show_traitAssocItems,
+            max_struct_field_count: self.data.hover_show_structFields,
         }
     }
 
@@ -1951,7 +1964,7 @@ where
 #[derive(Deserialize, Debug, Clone)]
 #[serde(untagged)]
 enum ManifestOrProjectJson {
-    Manifest(PathBuf),
+    Manifest(Utf8PathBuf),
     ProjectJson(ProjectJsonData),
 }
 
@@ -2134,7 +2147,7 @@ pub enum MemoryLayoutHoverRenderKindDef {
 #[serde(untagged)]
 pub enum TargetDirectory {
     UseSubdirectory(bool),
-    Directory(PathBuf),
+    Directory(Utf8PathBuf),
 }
 
 macro_rules! _config_data {
@@ -2263,7 +2276,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
             "type": "array",
             "items": { "type": "string" },
         },
-        "Vec<PathBuf>" => set! {
+        "Vec<Utf8PathBuf>" => set! {
             "type": "array",
             "items": { "type": "string" },
         },
@@ -2291,7 +2304,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
         "Option<String>" => set! {
             "type": ["null", "string"],
         },
-        "Option<PathBuf>" => set! {
+        "Option<Utf8PathBuf>" => set! {
             "type": ["null", "string"],
         },
         "Option<bool>" => set! {
@@ -2774,7 +2787,7 @@ mod tests {
             .unwrap();
         assert_eq!(config.data.cargo_targetDir, Some(TargetDirectory::UseSubdirectory(true)));
         assert!(
-            matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(PathBuf::from("target/rust-analyzer")))
+            matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(Utf8PathBuf::from("target/rust-analyzer")))
         );
     }
 
@@ -2793,10 +2806,10 @@ mod tests {
             .unwrap();
         assert_eq!(
             config.data.cargo_targetDir,
-            Some(TargetDirectory::Directory(PathBuf::from("other_folder")))
+            Some(TargetDirectory::Directory(Utf8PathBuf::from("other_folder")))
         );
         assert!(
-            matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(PathBuf::from("other_folder")))
+            matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(Utf8PathBuf::from("other_folder")))
         );
     }
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
index 6e6cc53c251..7c4deac93f2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -519,14 +519,13 @@ fn clippy_code_description(code: Option<&str>) -> Option<lsp_types::CodeDescript
 #[cfg(test)]
 #[cfg(not(windows))]
 mod tests {
-    use std::path::Path;
-
     use crate::{config::Config, global_state::GlobalState};
 
     use super::*;
 
     use expect_test::{expect_file, ExpectFile};
     use lsp_types::ClientCapabilities;
+    use paths::Utf8Path;
 
     fn check(diagnostics_json: &str, expect: ExpectFile) {
         check_with_config(DiagnosticsMapConfig::default(), diagnostics_json, expect)
@@ -534,7 +533,7 @@ mod tests {
 
     fn check_with_config(config: DiagnosticsMapConfig, diagnostics_json: &str, expect: ExpectFile) {
         let diagnostic: flycheck::Diagnostic = serde_json::from_str(diagnostics_json).unwrap();
-        let workspace_root: &AbsPath = Path::new("/test/").try_into().unwrap();
+        let workspace_root: &AbsPath = Utf8Path::new("/test/").try_into().unwrap();
         let (sender, _) = crossbeam_channel::unbounded();
         let state = GlobalState::new(
             sender,
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 1b4c33d8586..8516ffa0dfa 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
@@ -307,16 +307,18 @@ impl GlobalState {
             for file in changed_files {
                 let vfs_path = vfs.file_path(file.file_id);
                 if let Some(path) = vfs_path.as_path() {
-                    let path = path.to_path_buf();
-                    if reload::should_refresh_for_change(&path, file.kind()) {
-                        workspace_structure_change = Some((path.clone(), false));
+                    has_structure_changes = file.is_created_or_deleted();
+
+                    if file.is_modified() && path.extension() == Some("rs") {
+                        modified_rust_files.push(file.file_id);
                     }
+
+                    let path = path.to_path_buf();
                     if file.is_created_or_deleted() {
-                        has_structure_changes = true;
-                        workspace_structure_change =
-                            Some((path, self.crate_graph_file_dependencies.contains(vfs_path)));
-                    } else if path.extension() == Some("rs".as_ref()) {
-                        modified_rust_files.push(file.file_id);
+                        workspace_structure_change.get_or_insert((path, false)).1 |=
+                            self.crate_graph_file_dependencies.contains(vfs_path);
+                    } else if reload::should_refresh_for_change(&path, file.kind()) {
+                        workspace_structure_change.get_or_insert((path.clone(), false));
                     }
                 }
 
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 ff213748b4f..b5c4a4f435e 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
@@ -241,7 +241,7 @@ pub(crate) fn handle_did_change_watched_files(
     state: &mut GlobalState,
     params: DidChangeWatchedFilesParams,
 ) -> anyhow::Result<()> {
-    for change in params.changes {
+    for change in params.changes.iter().unique_by(|&it| &it.uri) {
         if let Ok(path) = from_proto::abs_path(&change.uri) {
             state.loader.handle.invalidate(path);
         }
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 1d98457add3..77692ed3ae7 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
@@ -4,7 +4,6 @@
 use std::{
     fs,
     io::Write as _,
-    path::PathBuf,
     process::{self, Stdio},
 };
 
@@ -12,8 +11,8 @@ use anyhow::Context;
 
 use ide::{
     AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange,
-    HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, RangeInfo, RangeLimit,
-    ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
+    HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory,
+    Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
 };
 use ide_db::SymbolKind;
 use itertools::Itertools;
@@ -27,6 +26,7 @@ use lsp_types::{
     SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult,
     SemanticTokensResult, SymbolInformation, SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
 };
+use paths::Utf8PathBuf;
 use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
 use serde_json::json;
 use stdx::{format_to, never};
@@ -238,9 +238,12 @@ pub(crate) fn handle_discover_test(
     let (tests, scope) = match params.test_id {
         Some(id) => {
             let crate_id = id.split_once("::").map(|it| it.0).unwrap_or(&id);
-            (snap.analysis.discover_tests_in_crate_by_test_id(crate_id)?, vec![crate_id.to_owned()])
+            (
+                snap.analysis.discover_tests_in_crate_by_test_id(crate_id)?,
+                Some(vec![crate_id.to_owned()]),
+            )
         }
-        None => (snap.analysis.discover_test_roots()?, vec![]),
+        None => (snap.analysis.discover_test_roots()?, None),
     };
     for t in &tests {
         hack_recover_crate_name::insert_name(t.id.clone());
@@ -248,12 +251,13 @@ pub(crate) fn handle_discover_test(
     Ok(lsp_ext::DiscoverTestResults {
         tests: tests
             .into_iter()
-            .map(|t| {
+            .filter_map(|t| {
                 let line_index = t.file.and_then(|f| snap.file_line_index(f).ok());
                 to_proto::test_item(&snap, t, line_index.as_ref())
             })
             .collect(),
         scope,
+        scope_file: None,
     })
 }
 
@@ -1465,7 +1469,7 @@ pub(crate) fn handle_inlay_hints(
     let inlay_hints_config = snap.config.inlay_hints();
     Ok(Some(
         snap.analysis
-            .inlay_hints(&inlay_hints_config, file_id, Some(RangeLimit::Fixed(range)))?
+            .inlay_hints(&inlay_hints_config, file_id, Some(range))?
             .into_iter()
             .map(|it| {
                 to_proto::inlay_hint(
@@ -1499,10 +1503,11 @@ pub(crate) fn handle_inlay_hints_resolve(
     let hint_position = from_proto::offset(&line_index, original_hint.position)?;
     let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
     forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
-    let resolve_hints = snap.analysis.inlay_hints(
+    let resolve_hints = snap.analysis.inlay_hints_resolve(
         &forced_resolve_inlay_hints_config,
         file_id,
-        Some(RangeLimit::NearestParent(hint_position)),
+        hint_position,
+        resolve_data.hash,
     )?;
 
     let mut resolved_hints = resolve_hints
@@ -1542,7 +1547,7 @@ pub(crate) fn handle_call_hierarchy_prepare(
     let RangeInfo { range: _, info: navs } = nav_info;
     let res = navs
         .into_iter()
-        .filter(|it| it.kind == Some(SymbolKind::Function))
+        .filter(|it| matches!(it.kind, Some(SymbolKind::Function | SymbolKind::Method)))
         .map(|it| to_proto::call_hierarchy_item(&snap, it))
         .collect::<Cancellable<Vec<_>>>()?;
 
@@ -1736,8 +1741,8 @@ pub(crate) fn handle_open_docs(
         _ => (None, None),
     };
 
-    let sysroot = sysroot.map(|p| p.root().as_os_str());
-    let target_dir = cargo.map(|cargo| cargo.target_directory()).map(|p| p.as_os_str());
+    let sysroot = sysroot.map(|p| p.root().as_str());
+    let target_dir = cargo.map(|cargo| cargo.target_directory()).map(|p| p.as_str());
 
     let Ok(remote_urls) = snap.analysis.external_docs(position, target_dir, sysroot) else {
         return if snap.config.local_docs() {
@@ -2042,7 +2047,7 @@ fn run_rustfmt(
             cmd
         }
         RustfmtConfig::CustomCommand { command, args } => {
-            let cmd = PathBuf::from(&command);
+            let cmd = Utf8PathBuf::from(&command);
             let workspace = CargoTargetSpec::for_file(snap, file_id)?;
             let mut cmd = match workspace {
                 Some(spec) => {
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 1c5a862c703..2731e845f35 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
@@ -52,7 +52,7 @@ fn integrated_highlighting_benchmark() {
 
     let file_id = {
         let file = workspace_to_load.join(file);
-        let path = VfsPath::from(AbsPathBuf::assert(file));
+        let path = VfsPath::from(AbsPathBuf::assert_utf8(file));
         vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}"))
     };
 
@@ -112,7 +112,7 @@ fn integrated_completion_benchmark() {
 
     let file_id = {
         let file = workspace_to_load.join(file);
-        let path = VfsPath::from(AbsPathBuf::assert(file));
+        let path = VfsPath::from(AbsPathBuf::assert_utf8(file));
         vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}"))
     };
 
@@ -274,7 +274,7 @@ fn integrated_diagnostics_benchmark() {
 
     let file_id = {
         let file = workspace_to_load.join(file);
-        let path = VfsPath::from(AbsPathBuf::assert(file));
+        let path = VfsPath::from(AbsPathBuf::assert_utf8(file));
         vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}"))
     };
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
index 710ce7f8acb..eac982f1b27 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
@@ -194,7 +194,8 @@ pub struct TestItem {
 #[serde(rename_all = "camelCase")]
 pub struct DiscoverTestResults {
     pub tests: Vec<TestItem>,
-    pub scope: Vec<String>,
+    pub scope: Option<Vec<String>>,
+    pub scope_file: Option<Vec<TextDocumentIdentifier>>,
 }
 
 pub enum DiscoverTest {}
@@ -800,6 +801,7 @@ pub struct CompletionResolveData {
 #[derive(Debug, Serialize, Deserialize)]
 pub struct InlayHintResolveData {
     pub file_id: u32,
+    pub hash: u64,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs
index c5081c4bea0..3e00222b752 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs
@@ -127,13 +127,14 @@ macro_rules! define_semantic_token_modifiers {
 
 define_semantic_token_modifiers![
     standard {
+        ASYNC,
         DOCUMENTATION,
         DECLARATION,
         STATIC,
         DEFAULT_LIBRARY,
     }
     custom {
-        (ASYNC, "async"),
+        (ASSOCIATED, "associated"),
         (ATTRIBUTE_MODIFIER, "attribute"),
         (CALLABLE, "callable"),
         (CONSTANT, "constant"),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index e77d0c13bf2..d8bb12528b9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -1,7 +1,7 @@
 //! Conversion of rust-analyzer specific types to lsp_types equivalents.
 use std::{
     iter::once,
-    mem, path,
+    mem,
     sync::atomic::{AtomicU32, Ordering},
 };
 
@@ -13,8 +13,9 @@ use ide::{
     NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
     SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
 };
-use ide_db::rust_doc::format_docs;
+use ide_db::{rust_doc::format_docs, FxHasher};
 use itertools::Itertools;
+use paths::{Utf8Component, Utf8Prefix};
 use semver::VersionReq;
 use serde_json::to_value;
 use vfs::AbsPath;
@@ -52,6 +53,7 @@ pub(crate) fn range(line_index: &LineIndex, range: TextRange) -> lsp_types::Rang
 pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind {
     match symbol_kind {
         SymbolKind::Function => lsp_types::SymbolKind::FUNCTION,
+        SymbolKind::Method => lsp_types::SymbolKind::METHOD,
         SymbolKind::Struct => lsp_types::SymbolKind::STRUCT,
         SymbolKind::Enum => lsp_types::SymbolKind::ENUM,
         SymbolKind::Variant => lsp_types::SymbolKind::ENUM_MEMBER,
@@ -122,12 +124,12 @@ pub(crate) fn completion_item_kind(
         CompletionItemKind::BuiltinType => lsp_types::CompletionItemKind::STRUCT,
         CompletionItemKind::InferredType => lsp_types::CompletionItemKind::SNIPPET,
         CompletionItemKind::Keyword => lsp_types::CompletionItemKind::KEYWORD,
-        CompletionItemKind::Method => lsp_types::CompletionItemKind::METHOD,
         CompletionItemKind::Snippet => lsp_types::CompletionItemKind::SNIPPET,
         CompletionItemKind::UnresolvedReference => lsp_types::CompletionItemKind::REFERENCE,
         CompletionItemKind::Expression => lsp_types::CompletionItemKind::SNIPPET,
         CompletionItemKind::SymbolKind(symbol) => match symbol {
             SymbolKind::Attribute => lsp_types::CompletionItemKind::FUNCTION,
+            SymbolKind::Method => lsp_types::CompletionItemKind::METHOD,
             SymbolKind::Const => lsp_types::CompletionItemKind::CONSTANT,
             SymbolKind::ConstParam => lsp_types::CompletionItemKind::TYPE_PARAMETER,
             SymbolKind::Derive => lsp_types::CompletionItemKind::FUNCTION,
@@ -444,30 +446,42 @@ pub(crate) fn inlay_hint(
     fields_to_resolve: &InlayFieldsToResolve,
     line_index: &LineIndex,
     file_id: FileId,
-    inlay_hint: InlayHint,
+    mut inlay_hint: InlayHint,
 ) -> Cancellable<lsp_types::InlayHint> {
-    let needs_resolve = inlay_hint.needs_resolve;
-    let (label, tooltip, mut something_to_resolve) =
-        inlay_hint_label(snap, fields_to_resolve, needs_resolve, inlay_hint.label)?;
+    let resolve_hash = inlay_hint.needs_resolve().then(|| {
+        std::hash::BuildHasher::hash_one(
+            &std::hash::BuildHasherDefault::<FxHasher>::default(),
+            &inlay_hint,
+        )
+    });
 
+    let mut something_to_resolve = false;
     let text_edits = if snap
         .config
         .visual_studio_code_version()
         // https://github.com/microsoft/vscode/issues/193124
         .map_or(true, |version| VersionReq::parse(">=1.86.0").unwrap().matches(version))
-        && needs_resolve
+        && resolve_hash.is_some()
         && fields_to_resolve.resolve_text_edits
     {
         something_to_resolve |= inlay_hint.text_edit.is_some();
         None
     } else {
-        inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it))
+        inlay_hint.text_edit.take().map(|it| text_edit_vec(line_index, it))
     };
-
-    let data = if needs_resolve && something_to_resolve {
-        Some(to_value(lsp_ext::InlayHintResolveData { file_id: file_id.index() }).unwrap())
-    } else {
-        None
+    let (label, tooltip) = inlay_hint_label(
+        snap,
+        fields_to_resolve,
+        &mut something_to_resolve,
+        resolve_hash.is_some(),
+        inlay_hint.label,
+    )?;
+
+    let data = match resolve_hash {
+        Some(hash) if something_to_resolve => Some(
+            to_value(lsp_ext::InlayHintResolveData { file_id: file_id.index(), hash }).unwrap(),
+        ),
+        _ => None,
     };
 
     Ok(lsp_types::InlayHint {
@@ -492,15 +506,15 @@ pub(crate) fn inlay_hint(
 fn inlay_hint_label(
     snap: &GlobalStateSnapshot,
     fields_to_resolve: &InlayFieldsToResolve,
+    something_to_resolve: &mut bool,
     needs_resolve: bool,
     mut label: InlayHintLabel,
-) -> Cancellable<(lsp_types::InlayHintLabel, Option<lsp_types::InlayHintTooltip>, bool)> {
-    let mut something_to_resolve = false;
+) -> Cancellable<(lsp_types::InlayHintLabel, Option<lsp_types::InlayHintTooltip>)> {
     let (label, tooltip) = match &*label.parts {
         [InlayHintLabelPart { linked_location: None, .. }] => {
             let InlayHintLabelPart { text, tooltip, .. } = label.parts.pop().unwrap();
             let hint_tooltip = if needs_resolve && fields_to_resolve.resolve_hint_tooltip {
-                something_to_resolve |= tooltip.is_some();
+                *something_to_resolve |= tooltip.is_some();
                 None
             } else {
                 match tooltip {
@@ -524,7 +538,7 @@ fn inlay_hint_label(
                 .into_iter()
                 .map(|part| {
                     let tooltip = if needs_resolve && fields_to_resolve.resolve_label_tooltip {
-                        something_to_resolve |= part.tooltip.is_some();
+                        *something_to_resolve |= part.tooltip.is_some();
                         None
                     } else {
                         match part.tooltip {
@@ -543,7 +557,7 @@ fn inlay_hint_label(
                         }
                     };
                     let location = if needs_resolve && fields_to_resolve.resolve_label_location {
-                        something_to_resolve |= part.linked_location.is_some();
+                        *something_to_resolve |= part.linked_location.is_some();
                         None
                     } else {
                         part.linked_location.map(|range| location(snap, range)).transpose()?
@@ -559,7 +573,7 @@ fn inlay_hint_label(
             (lsp_types::InlayHintLabel::LabelParts(parts), None)
         }
     };
-    Ok((label, tooltip, something_to_resolve))
+    Ok((label, tooltip))
 }
 
 static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);
@@ -636,8 +650,7 @@ pub(crate) fn semantic_token_delta(
 fn semantic_token_type_and_modifiers(
     highlight: Highlight,
 ) -> (lsp_types::SemanticTokenType, semantic_tokens::ModifierSet) {
-    let mut mods = semantic_tokens::ModifierSet::default();
-    let type_ = match highlight.tag {
+    let ty = match highlight.tag {
         HlTag::Symbol(symbol) => match symbol {
             SymbolKind::Attribute => semantic_tokens::DECORATOR,
             SymbolKind::Derive => semantic_tokens::DERIVE,
@@ -653,22 +666,10 @@ fn semantic_token_type_and_modifiers(
             SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD,
             SymbolKind::SelfType => semantic_tokens::SELF_TYPE_KEYWORD,
             SymbolKind::Local => semantic_tokens::VARIABLE,
-            SymbolKind::Function => {
-                if highlight.mods.contains(HlMod::Associated) {
-                    semantic_tokens::METHOD
-                } else {
-                    semantic_tokens::FUNCTION
-                }
-            }
-            SymbolKind::Const => {
-                mods |= semantic_tokens::CONSTANT;
-                mods |= semantic_tokens::STATIC;
-                semantic_tokens::VARIABLE
-            }
-            SymbolKind::Static => {
-                mods |= semantic_tokens::STATIC;
-                semantic_tokens::VARIABLE
-            }
+            SymbolKind::Method => semantic_tokens::METHOD,
+            SymbolKind::Function => semantic_tokens::FUNCTION,
+            SymbolKind::Const => semantic_tokens::VARIABLE,
+            SymbolKind::Static => semantic_tokens::VARIABLE,
             SymbolKind::Struct => semantic_tokens::STRUCT,
             SymbolKind::Enum => semantic_tokens::ENUM,
             SymbolKind::Variant => semantic_tokens::ENUM_MEMBER,
@@ -715,12 +716,14 @@ fn semantic_token_type_and_modifiers(
         },
     };
 
+    let mut mods = semantic_tokens::ModifierSet::default();
     for modifier in highlight.mods.iter() {
         let modifier = match modifier {
-            HlMod::Associated => continue,
+            HlMod::Associated => semantic_tokens::ASSOCIATED,
             HlMod::Async => semantic_tokens::ASYNC,
             HlMod::Attribute => semantic_tokens::ATTRIBUTE_MODIFIER,
             HlMod::Callable => semantic_tokens::CALLABLE,
+            HlMod::Const => semantic_tokens::CONSTANT,
             HlMod::Consuming => semantic_tokens::CONSUMING,
             HlMod::ControlFlow => semantic_tokens::CONTROL_FLOW,
             HlMod::CrateRoot => semantic_tokens::CRATE_ROOT,
@@ -742,7 +745,7 @@ fn semantic_token_type_and_modifiers(
         mods |= modifier;
     }
 
-    (type_, mods)
+    (ty, mods)
 }
 
 pub(crate) fn folding_range(
@@ -814,9 +817,9 @@ pub(crate) fn url(snap: &GlobalStateSnapshot, file_id: FileId) -> lsp_types::Url
 /// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
 pub(crate) fn url_from_abs_path(path: &AbsPath) -> lsp_types::Url {
     let url = lsp_types::Url::from_file_path(path).unwrap();
-    match path.as_ref().components().next() {
-        Some(path::Component::Prefix(prefix))
-            if matches!(prefix.kind(), path::Prefix::Disk(_) | path::Prefix::VerbatimDisk(_)) =>
+    match path.components().next() {
+        Some(Utf8Component::Prefix(prefix))
+            if matches!(prefix.kind(), Utf8Prefix::Disk(_) | Utf8Prefix::VerbatimDisk(_)) =>
         {
             // Need to lowercase driver letter
         }
@@ -1514,8 +1517,8 @@ pub(crate) fn test_item(
     snap: &GlobalStateSnapshot,
     test_item: ide::TestItem,
     line_index: Option<&LineIndex>,
-) -> lsp_ext::TestItem {
-    lsp_ext::TestItem {
+) -> Option<lsp_ext::TestItem> {
+    Some(lsp_ext::TestItem {
         id: test_item.id,
         label: test_item.label,
         kind: match test_item.kind {
@@ -1530,9 +1533,9 @@ pub(crate) fn test_item(
                     | project_model::TargetKind::Example
                     | project_model::TargetKind::BuildScript
                     | project_model::TargetKind::Other => lsp_ext::TestItemKind::Package,
-                    project_model::TargetKind::Test | project_model::TargetKind::Bench => {
-                        lsp_ext::TestItemKind::Test
-                    }
+                    project_model::TargetKind::Test => lsp_ext::TestItemKind::Test,
+                    // benches are not tests needed to be shown in the test explorer
+                    project_model::TargetKind::Bench => return None,
                 }
             }
             ide::TestItemKind::Module => lsp_ext::TestItemKind::Module,
@@ -1548,7 +1551,7 @@ pub(crate) fn test_item(
             .map(|f| lsp_types::TextDocumentIdentifier { uri: url(snap, f) }),
         range: line_index.and_then(|l| Some(range(l, test_item.text_range?))),
         runnable: test_item.runnable.and_then(|r| runnable(snap, r).ok()),
-    }
+    })
 }
 
 pub(crate) mod command {
@@ -2728,12 +2731,12 @@ struct ProcMacro {
     #[test]
     #[cfg(target_os = "windows")]
     fn test_lowercase_drive_letter() {
-        use std::path::Path;
+        use paths::Utf8Path;
 
-        let url = url_from_abs_path(Path::new("C:\\Test").try_into().unwrap());
+        let url = url_from_abs_path(Utf8Path::new("C:\\Test").try_into().unwrap());
         assert_eq!(url.to_string(), "file:///c:/Test");
 
-        let url = url_from_abs_path(Path::new(r#"\\localhost\C$\my_dir"#).try_into().unwrap());
+        let url = url_from_abs_path(Utf8Path::new(r#"\\localhost\C$\my_dir"#).try_into().unwrap());
         assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
     }
 }
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 ffe56e41435..38df3235125 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
@@ -9,9 +9,8 @@ use std::{
 use always_assert::always;
 use crossbeam_channel::{never, select, Receiver};
 use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath};
-use itertools::Itertools;
 use lsp_server::{Connection, Notification, Request};
-use lsp_types::notification::Notification as _;
+use lsp_types::{notification::Notification as _, TextDocumentIdentifier};
 use stdx::thread::ThreadIntent;
 use vfs::FileId;
 
@@ -533,31 +532,29 @@ impl GlobalState {
             let snapshot = self.snapshot();
             move || {
                 let tests = subscriptions
-                    .into_iter()
-                    .filter_map(|f| snapshot.analysis.crates_for(f).ok())
-                    .flatten()
-                    .unique()
-                    .filter_map(|c| snapshot.analysis.discover_tests_in_crate(c).ok())
+                    .iter()
+                    .copied()
+                    .filter_map(|f| snapshot.analysis.discover_tests_in_file(f).ok())
                     .flatten()
                     .collect::<Vec<_>>();
                 for t in &tests {
                     hack_recover_crate_name::insert_name(t.id.clone());
                 }
-                let scope = tests
-                    .iter()
-                    .filter_map(|t| Some(t.id.split_once("::")?.0))
-                    .unique()
-                    .map(|it| it.to_owned())
-                    .collect();
                 Task::DiscoverTest(lsp_ext::DiscoverTestResults {
                     tests: tests
                         .into_iter()
-                        .map(|t| {
+                        .filter_map(|t| {
                             let line_index = t.file.and_then(|f| snapshot.file_line_index(f).ok());
                             to_proto::test_item(&snapshot, t, line_index.as_ref())
                         })
                         .collect(),
-                    scope,
+                    scope: None,
+                    scope_file: Some(
+                        subscriptions
+                            .into_iter()
+                            .map(|f| TextDocumentIdentifier { uri: to_proto::url(&snapshot, f) })
+                            .collect(),
+                    ),
                 })
             }
         });
@@ -653,7 +650,7 @@ impl GlobalState {
                 };
 
                 if let Some(state) = state {
-                    self.report_progress("Building", state, msg, None, None);
+                    self.report_progress("Building build-artifacts", state, msg, None, None);
                 }
             }
             Task::LoadProcMacros(progress) => {
@@ -669,7 +666,7 @@ impl GlobalState {
                 };
 
                 if let Some(state) = state {
-                    self.report_progress("Loading", state, msg, None, None);
+                    self.report_progress("Loading proc-macros", state, msg, None, None);
                 }
             }
             Task::BuildDepsHaveChanged => self.build_deps_changed = true,
@@ -714,10 +711,9 @@ impl GlobalState {
                     message += &format!(
                         ": {}",
                         match dir.strip_prefix(self.config.root_path()) {
-                            Some(relative_path) => relative_path.as_ref(),
+                            Some(relative_path) => relative_path.as_utf8_path(),
                             None => dir.as_ref(),
                         }
-                        .display()
                     );
                 }
 
@@ -861,7 +857,7 @@ impl GlobalState {
                 let title = if self.flycheck.len() == 1 {
                     format!("{}", self.config.flycheck())
                 } else {
-                    format!("cargo check (#{})", id + 1)
+                    format!("{} (#{})", self.config.flycheck(), id + 1)
                 };
                 self.report_progress(
                     &title,
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 c2725e1fad9..771a5599f6f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -26,7 +26,6 @@ use itertools::Itertools;
 use load_cargo::{load_proc_macro, ProjectFolders};
 use proc_macro_api::ProcMacroServer;
 use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
-use rustc_hash::FxHashSet;
 use stdx::{format_to, thread::ThreadIntent};
 use triomphe::Arc;
 use vfs::{AbsPath, AbsPathBuf, ChangeKind};
@@ -185,10 +184,8 @@ impl GlobalState {
                 message.push_str(
                     "`rust-analyzer.linkedProjects` have been specified, which may be incorrect. Specified project paths:\n",
                 );
-                message.push_str(&format!(
-                    "    {}",
-                    self.config.linked_manifests().map(|it| it.display()).format("\n    ")
-                ));
+                message
+                    .push_str(&format!("    {}", self.config.linked_manifests().format("\n    ")));
                 if self.config.has_linked_project_jsons() {
                     message.push_str("\nAdditionally, one or more project jsons are specified")
                 }
@@ -431,27 +428,46 @@ impl GlobalState {
         }
 
         if let FilesWatcher::Client = self.config.files().watcher {
-            let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions {
-                watchers: self
-                    .workspaces
-                    .iter()
-                    .flat_map(|ws| ws.to_roots())
-                    .filter(|it| it.is_local)
+            let filter =
+                self.workspaces.iter().flat_map(|ws| ws.to_roots()).filter(|it| it.is_local);
+
+            let watchers = if self.config.did_change_watched_files_relative_pattern_support() {
+                // When relative patterns are supported by the client, prefer using them
+                filter
+                    .flat_map(|root| {
+                        root.include.into_iter().flat_map(|base| {
+                            [(base.clone(), "**/*.rs"), (base, "**/Cargo.{lock,toml}")]
+                        })
+                    })
+                    .map(|(base, pat)| lsp_types::FileSystemWatcher {
+                        glob_pattern: lsp_types::GlobPattern::Relative(
+                            lsp_types::RelativePattern {
+                                base_uri: lsp_types::OneOf::Right(
+                                    lsp_types::Url::from_file_path(base).unwrap(),
+                                ),
+                                pattern: pat.to_owned(),
+                            },
+                        ),
+                        kind: None,
+                    })
+                    .collect()
+            } else {
+                // When they're not, integrate the base to make them into absolute patterns
+                filter
                     .flat_map(|root| {
-                        root.include.into_iter().flat_map(|it| {
-                            [
-                                format!("{it}/**/*.rs"),
-                                format!("{it}/**/Cargo.toml"),
-                                format!("{it}/**/Cargo.lock"),
-                            ]
+                        root.include.into_iter().flat_map(|base| {
+                            [format!("{base}/**/*.rs"), format!("{base}/**/Cargo.{{lock,toml}}")]
                         })
                     })
                     .map(|glob_pattern| lsp_types::FileSystemWatcher {
                         glob_pattern: lsp_types::GlobPattern::String(glob_pattern),
                         kind: None,
                     })
-                    .collect(),
+                    .collect()
             };
+
+            let registration_options =
+                lsp_types::DidChangeWatchedFilesRegistrationOptions { watchers };
             let registration = lsp_types::Registration {
                 id: "workspace/didChangeWatchedFiles".to_owned(),
                 method: "workspace/didChangeWatchedFiles".to_owned(),
@@ -525,26 +541,23 @@ impl GlobalState {
     fn recreate_crate_graph(&mut self, cause: String) {
         // crate graph construction relies on these paths, record them so when one of them gets
         // deleted or created we trigger a reconstruction of the crate graph
-        let mut crate_graph_file_dependencies = FxHashSet::default();
+        let mut crate_graph_file_dependencies = mem::take(&mut self.crate_graph_file_dependencies);
+        self.report_progress(
+            "Building CrateGraph",
+            crate::lsp::utils::Progress::Begin,
+            None,
+            None,
+            None,
+        );
 
         let (crate_graph, proc_macro_paths, layouts, toolchains) = {
             // Create crate graph from all the workspaces
             let vfs = &mut self.vfs.write().0;
-            let loader = &mut self.loader;
 
             let load = |path: &AbsPath| {
-                let _p = tracing::span!(tracing::Level::DEBUG, "switch_workspaces::load").entered();
                 let vfs_path = vfs::VfsPath::from(path.to_path_buf());
                 crate_graph_file_dependencies.insert(vfs_path.clone());
-                match vfs.file_id(&vfs_path) {
-                    Some(file_id) => Some(file_id),
-                    None => {
-                        // FIXME: Consider not loading this here?
-                        let contents = loader.handle.load_sync(path);
-                        vfs.set_file_contents(vfs_path.clone(), contents);
-                        vfs.file_id(&vfs_path)
-                    }
-                }
+                vfs.file_id(&vfs_path)
             };
 
             ws_to_crate_graph(&self.workspaces, self.config.extra_env(), load)
@@ -564,6 +577,13 @@ impl GlobalState {
         change.set_toolchains(toolchains);
         self.analysis_host.apply_change(change);
         self.crate_graph_file_dependencies = crate_graph_file_dependencies;
+        self.report_progress(
+            "Building CrateGraph",
+            crate::lsp::utils::Progress::End,
+            None,
+            None,
+            None,
+        );
 
         self.process_changes();
         self.reload_flycheck();
@@ -732,6 +752,8 @@ pub fn ws_to_crate_graph(
         });
         proc_macro_paths.push(crate_proc_macros);
     }
+    crate_graph.shrink_to_fit();
+    proc_macro_paths.shrink_to_fit();
     (crate_graph, proc_macro_paths, layouts, toolchains)
 }
 
@@ -739,7 +761,7 @@ pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind)
     const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
     const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
 
-    let file_name = match path.file_name().unwrap_or_default().to_str() {
+    let file_name = match path.file_name() {
         Some(it) => it,
         None => return false,
     };
@@ -754,18 +776,18 @@ pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind)
     // .cargo/config{.toml}
     if path.extension().unwrap_or_default() != "rs" {
         let is_cargo_config = matches!(file_name, "config.toml" | "config")
-            && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")).unwrap_or(false);
+            && path.parent().map(|parent| parent.as_str().ends_with(".cargo")).unwrap_or(false);
         return is_cargo_config;
     }
 
-    if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) {
+    if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_str().ends_with(it)) {
         return true;
     }
     let parent = match path.parent() {
         Some(it) => it,
         None => return false,
     };
-    if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.as_ref().ends_with(it)) {
+    if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.as_str().ends_with(it)) {
         return true;
     }
     if file_name == "main.rs" {
@@ -773,7 +795,7 @@ pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind)
             Some(it) => it,
             None => return false,
         };
-        if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.as_ref().ends_with(it)) {
+        if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.as_str().ends_with(it)) {
             return true;
         }
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs
index efd42fadf7e..cf38032b941 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs
@@ -60,7 +60,7 @@ fn get_fake_sysroot() -> Sysroot {
     let sysroot_path = get_fake_sysroot_path();
     // there's no `libexec/` directory with a `proc-macro-srv` binary in that
     // fake sysroot, so we give them both the same path:
-    let sysroot_dir = AbsPathBuf::assert(sysroot_path);
+    let sysroot_dir = AbsPathBuf::assert_utf8(sysroot_path);
     let sysroot_src_dir = sysroot_dir.clone();
     Sysroot::load(sysroot_dir, Some(Ok(sysroot_src_dir)), false)
 }
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 960f5b531d4..439b006977d 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
@@ -903,6 +903,7 @@ fn out_dirs_check() {
 }
 
 #[test]
+#[cfg(not(windows))] // windows requires elevated permissions to create symlinks
 fn root_contains_symlink_out_dirs_check() {
     out_dirs_check_impl(true);
 }
@@ -917,7 +918,7 @@ fn resolve_proc_macro() {
     }
 
     let sysroot = project_model::Sysroot::discover_no_source(
-        &AbsPathBuf::assert(std::env::current_dir().unwrap()),
+        &AbsPathBuf::assert_utf8(std::env::current_dir().unwrap()),
         &Default::default(),
     )
     .unwrap();
@@ -1002,7 +1003,7 @@ pub fn foo(_input: TokenStream) -> TokenStream {
         },
         "procMacro": {
             "enable": true,
-            "server": proc_macro_server_path.as_path().as_ref(),
+            "server": proc_macro_server_path.as_path().as_str(),
         }
     }))
     .root("foo")
@@ -1039,7 +1040,7 @@ fn test_will_rename_files_same_level() {
 
     let tmp_dir = TestDir::new();
     let tmp_dir_path = tmp_dir.path().to_owned();
-    let tmp_dir_str = tmp_dir_path.to_str().unwrap();
+    let tmp_dir_str = tmp_dir_path.as_str();
     let base_path = PathBuf::from(format!("file://{tmp_dir_str}"));
 
     let code = r#"
@@ -1084,7 +1085,7 @@ use crate::old_folder::nested::foo as bar;
           "documentChanges": [
             {
               "textDocument": {
-                "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_owned().replace("C:\\", "/c:/").replace('\\', "/")),
+                "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").as_str().to_owned().replace("C:\\", "/c:/").replace('\\', "/")),
                 "version": null
               },
               "edits": [
@@ -1141,7 +1142,7 @@ use crate::old_folder::nested::foo as bar;
           "documentChanges": [
             {
               "textDocument": {
-                "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_owned().replace("C:\\", "/c:/").replace('\\', "/")),
+                "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").as_str().to_owned().replace("C:\\", "/c:/").replace('\\', "/")),
                 "version": null
               },
               "edits": [
@@ -1162,7 +1163,7 @@ use crate::old_folder::nested::foo as bar;
             },
             {
               "textDocument": {
-                "uri": format!("file://{}", tmp_dir_path.join("src").join("old_folder").join("nested.rs").to_str().unwrap().to_owned().replace("C:\\", "/c:/").replace('\\', "/")),
+                "uri": format!("file://{}", tmp_dir_path.join("src").join("old_folder").join("nested.rs").as_str().to_owned().replace("C:\\", "/c:/").replace('\\', "/")),
                 "version": null
               },
               "edits": [
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index 1d831b8b105..8bbe6ff3724 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -1,7 +1,6 @@
 use std::{
     cell::{Cell, RefCell},
     fs,
-    path::{Path, PathBuf},
     sync::Once,
     time::Duration,
 };
@@ -9,6 +8,7 @@ use std::{
 use crossbeam_channel::{after, select, Receiver};
 use lsp_server::{Connection, Message, Notification, Request};
 use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url};
+use paths::{Utf8Path, Utf8PathBuf};
 use rust_analyzer::{config::Config, lsp, main_loop};
 use serde::Serialize;
 use serde_json::{json, to_string_pretty, Value};
@@ -21,7 +21,7 @@ use crate::testdir::TestDir;
 pub(crate) struct Project<'a> {
     fixture: &'a str,
     tmp_dir: Option<TestDir>,
-    roots: Vec<PathBuf>,
+    roots: Vec<Utf8PathBuf>,
     config: serde_json::Value,
     root_dir_contains_symlink: bool,
 }
@@ -359,7 +359,7 @@ impl Server {
         self.client.sender.send(Message::Notification(not)).unwrap();
     }
 
-    pub(crate) fn path(&self) -> &Path {
+    pub(crate) fn path(&self) -> &Utf8Path {
         self.dir.path()
     }
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs
index b3ee7fa3d03..d113bd51278 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs
@@ -1,11 +1,12 @@
 use std::{
     fs, io,
-    path::{Path, PathBuf},
     sync::atomic::{AtomicUsize, Ordering},
 };
 
+use paths::{Utf8Path, Utf8PathBuf};
+
 pub(crate) struct TestDir {
-    path: PathBuf,
+    path: Utf8PathBuf,
     keep: bool,
 }
 
@@ -51,10 +52,13 @@ impl TestDir {
                 #[cfg(target_os = "windows")]
                 std::os::windows::fs::symlink_dir(path, &symlink_path).unwrap();
 
-                return TestDir { path: symlink_path, keep: false };
+                return TestDir {
+                    path: Utf8PathBuf::from_path_buf(symlink_path).unwrap(),
+                    keep: false,
+                };
             }
 
-            return TestDir { path, keep: false };
+            return TestDir { path: Utf8PathBuf::from_path_buf(path).unwrap(), keep: false };
         }
         panic!("Failed to create a temporary directory")
     }
@@ -64,7 +68,7 @@ impl TestDir {
         self.keep = true;
         self
     }
-    pub(crate) fn path(&self) -> &Path {
+    pub(crate) fn path(&self) -> &Utf8Path {
         &self.path
     }
 }
@@ -79,7 +83,7 @@ impl Drop for TestDir {
         let actual_path = filetype.is_symlink().then(|| fs::read_link(&self.path).unwrap());
 
         if let Some(actual_path) = actual_path {
-            remove_dir_all(&actual_path).unwrap_or_else(|err| {
+            remove_dir_all(Utf8Path::from_path(&actual_path).unwrap()).unwrap_or_else(|err| {
                 panic!(
                     "failed to remove temporary link to directory {}: {err}",
                     actual_path.display()
@@ -88,18 +92,18 @@ impl Drop for TestDir {
         }
 
         remove_dir_all(&self.path).unwrap_or_else(|err| {
-            panic!("failed to remove temporary directory {}: {err}", self.path.display())
+            panic!("failed to remove temporary directory {}: {err}", self.path)
         });
     }
 }
 
 #[cfg(not(windows))]
-fn remove_dir_all(path: &Path) -> io::Result<()> {
+fn remove_dir_all(path: &Utf8Path) -> io::Result<()> {
     fs::remove_dir_all(path)
 }
 
 #[cfg(windows)]
-fn remove_dir_all(path: &Path) -> io::Result<()> {
+fn remove_dir_all(path: &Utf8Path) -> io::Result<()> {
     for _ in 0..99 {
         if fs::remove_dir_all(path).is_ok() {
             return Ok(());
diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs
index 6b849ce3738..c9109c72d0d 100644
--- a/src/tools/rust-analyzer/crates/span/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/span/src/lib.rs
@@ -16,6 +16,56 @@ pub use self::{
 pub use syntax::{TextRange, TextSize};
 pub use vfs::FileId;
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum Edition {
+    Edition2015,
+    Edition2018,
+    Edition2021,
+    Edition2024,
+}
+
+impl Edition {
+    pub const CURRENT: Edition = Edition::Edition2021;
+    pub const DEFAULT: Edition = Edition::Edition2015;
+}
+
+#[derive(Debug)]
+pub struct ParseEditionError {
+    invalid_input: String,
+}
+
+impl std::error::Error for ParseEditionError {}
+impl fmt::Display for ParseEditionError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "invalid edition: {:?}", self.invalid_input)
+    }
+}
+
+impl std::str::FromStr for Edition {
+    type Err = ParseEditionError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let res = match s {
+            "2015" => Edition::Edition2015,
+            "2018" => Edition::Edition2018,
+            "2021" => Edition::Edition2021,
+            "2024" => Edition::Edition2024,
+            _ => return Err(ParseEditionError { invalid_input: s.to_owned() }),
+        };
+        Ok(res)
+    }
+}
+
+impl fmt::Display for Edition {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(match self {
+            Edition::Edition2015 => "2015",
+            Edition::Edition2018 => "2018",
+            Edition::Edition2021 => "2021",
+            Edition::Edition2024 => "2024",
+        })
+    }
+}
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub struct FilePosition {
     pub file_id: FileId,
diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
index 9a8d73cf7ff..1809ca7dea5 100644
--- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
@@ -33,12 +33,8 @@ text-edit.workspace = true
 [dev-dependencies]
 rayon.workspace = true
 expect-test = "1.4.0"
-proc-macro2 = "1.0.47"
-quote = "1.0.20"
-ungrammar = "1.16.1"
 
 test-utils.workspace = true
-sourcegen.workspace = true
 
 [features]
 in-rust-tree = []
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index c3d8e97c436..e1765b25fd8 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -414,7 +414,7 @@ StmtList =
   '}'
 
 RefExpr =
-  Attr* '&' ('raw' | 'mut' | 'const') Expr
+  Attr* '&' (('raw' 'const'?)| ('raw'? 'mut') ) Expr
 
 TryExpr =
   Attr* Expr '?'
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 75971861aa8..c82bc4151ac 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -8,247 +8,269 @@ use crate::{
 };
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Name {
+pub struct Abi {
     pub(crate) syntax: SyntaxNode,
 }
-impl Name {
-    pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) }
-    pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
+impl Abi {
+    pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct NameRef {
+pub struct ArgList {
     pub(crate) syntax: SyntaxNode,
 }
-impl NameRef {
-    pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) }
-    pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
-    pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) }
-    pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
-    pub fn Self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![Self]) }
+impl ArgList {
+    pub fn args(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Lifetime {
+pub struct ArrayExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl Lifetime {
-    pub fn lifetime_ident_token(&self) -> Option<SyntaxToken> {
-        support::token(&self.syntax, T![lifetime_ident])
-    }
+impl ast::HasAttrs for ArrayExpr {}
+impl ArrayExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
+    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Path {
+pub struct ArrayType {
     pub(crate) syntax: SyntaxNode,
 }
-impl Path {
-    pub fn qualifier(&self) -> Option<Path> { support::child(&self.syntax) }
-    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
-    pub fn segment(&self) -> Option<PathSegment> { support::child(&self.syntax) }
+impl ArrayType {
+    pub fn const_arg(&self) -> Option<ConstArg> { support::child(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct PathSegment {
+pub struct AsmExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl PathSegment {
-    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
-    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
-    pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) }
-    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
-    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
-    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
-    pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) }
-    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
+impl ast::HasAttrs for AsmExpr {}
+impl AsmExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+    pub fn asm_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![asm]) }
+    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericArgList {
+pub struct AssocItemList {
     pub(crate) syntax: SyntaxNode,
 }
-impl GenericArgList {
-    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
-    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
-    pub fn generic_args(&self) -> AstChildren<GenericArg> { support::children(&self.syntax) }
-    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
+impl ast::HasAttrs for AssocItemList {}
+impl AssocItemList {
+    pub fn assoc_items(&self) -> AstChildren<AssocItem> { support::children(&self.syntax) }
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ParamList {
+pub struct AssocTypeArg {
     pub(crate) syntax: SyntaxNode,
 }
-impl ParamList {
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn self_param(&self) -> Option<SelfParam> { support::child(&self.syntax) }
-    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
-    pub fn params(&self) -> AstChildren<Param> { support::children(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
-    pub fn pipe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![|]) }
+impl ast::HasTypeBounds for AssocTypeArg {}
+impl AssocTypeArg {
+    pub fn const_arg(&self) -> Option<ConstArg> { support::child(&self.syntax) }
+    pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) }
+    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
+    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
+    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RetType {
+pub struct Attr {
     pub(crate) syntax: SyntaxNode,
 }
-impl RetType {
-    pub fn thin_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![->]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+impl Attr {
+    pub fn meta(&self) -> Option<Meta> { support::child(&self.syntax) }
+    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
+    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
+    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct PathType {
+pub struct AwaitExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl PathType {
-    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
+impl ast::HasAttrs for AwaitExpr {}
+impl AwaitExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
+    pub fn await_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![await]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TypeArg {
+pub struct BecomeExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl TypeArg {
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+impl ast::HasAttrs for BecomeExpr {}
+impl BecomeExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn become_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![become]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AssocTypeArg {
+pub struct BinExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasTypeBounds for AssocTypeArg {}
-impl AssocTypeArg {
-    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
-    pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) }
-    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
-    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
-    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    pub fn const_arg(&self) -> Option<ConstArg> { support::child(&self.syntax) }
+impl ast::HasAttrs for BinExpr {}
+impl BinExpr {}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct BlockExpr {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasAttrs for BlockExpr {}
+impl BlockExpr {
+    pub fn label(&self) -> Option<Label> { support::child(&self.syntax) }
+    pub fn stmt_list(&self) -> Option<StmtList> { support::child(&self.syntax) }
+    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
+    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
+    pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) }
+    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct LifetimeArg {
+pub struct BoxPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl LifetimeArg {
-    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
+impl BoxPat {
+    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
+    pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ConstArg {
+pub struct BreakExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ConstArg {
+impl ast::HasAttrs for BreakExpr {}
+impl BreakExpr {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
+    pub fn break_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![break]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TypeBoundList {
+pub struct CallExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl TypeBoundList {
-    pub fn bounds(&self) -> AstChildren<TypeBound> { support::children(&self.syntax) }
+impl ast::HasArgList for CallExpr {}
+impl ast::HasAttrs for CallExpr {}
+impl CallExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MacroCall {
+pub struct CastExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MacroCall {}
-impl ast::HasDocComments for MacroCall {}
-impl MacroCall {
-    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
-    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
-    pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
-    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+impl ast::HasAttrs for CastExpr {}
+impl CastExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Attr {
+pub struct ClosureExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl Attr {
-    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
-    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
-    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
-    pub fn meta(&self) -> Option<Meta> { support::child(&self.syntax) }
-    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+impl ast::HasAttrs for ClosureExpr {}
+impl ClosureExpr {
+    pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
+    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
+    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
+    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
+    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
+    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
+    pub fn move_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![move]) }
+    pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TokenTree {
+pub struct Const {
     pub(crate) syntax: SyntaxNode,
 }
-impl TokenTree {
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
-    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
-    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
-    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+impl ast::HasAttrs for Const {}
+impl ast::HasDocComments for Const {}
+impl ast::HasName for Const {}
+impl ast::HasVisibility for Const {}
+impl Const {
+    pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
+    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
+    pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MacroItems {
+pub struct ConstArg {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasModuleItem for MacroItems {}
-impl MacroItems {}
+impl ConstArg {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MacroEagerInput {
+pub struct ConstBlockPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl MacroEagerInput {
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
-    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
-    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
-    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+impl ConstBlockPat {
+    pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
+    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MacroStmts {
+pub struct ConstParam {
     pub(crate) syntax: SyntaxNode,
 }
-impl MacroStmts {
-    pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+impl ast::HasAttrs for ConstParam {}
+impl ast::HasName for ConstParam {}
+impl ConstParam {
+    pub fn default_val(&self) -> Option<ConstArg> { support::child(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct SourceFile {
+pub struct ContinueExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for SourceFile {}
-impl ast::HasModuleItem for SourceFile {}
-impl ast::HasDocComments for SourceFile {}
-impl SourceFile {
-    pub fn shebang_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![shebang]) }
+impl ast::HasAttrs for ContinueExpr {}
+impl ContinueExpr {
+    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
+    pub fn continue_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![continue])
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Const {
+pub struct DynTraitType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Const {}
-impl ast::HasName for Const {}
-impl ast::HasVisibility for Const {}
-impl ast::HasDocComments for Const {}
-impl Const {
-    pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
-    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
-    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
-    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+impl DynTraitType {
+    pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) }
+    pub fn dyn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![dyn]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -256,13 +278,22 @@ pub struct Enum {
     pub(crate) syntax: SyntaxNode,
 }
 impl ast::HasAttrs for Enum {}
+impl ast::HasDocComments for Enum {}
+impl ast::HasGenericParams for Enum {}
 impl ast::HasName for Enum {}
 impl ast::HasVisibility for Enum {}
-impl ast::HasGenericParams for Enum {}
-impl ast::HasDocComments for Enum {}
 impl Enum {
-    pub fn enum_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![enum]) }
     pub fn variant_list(&self) -> Option<VariantList> { support::child(&self.syntax) }
+    pub fn enum_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![enum]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprStmt {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ExprStmt {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -272,9 +303,9 @@ pub struct ExternBlock {
 impl ast::HasAttrs for ExternBlock {}
 impl ast::HasDocComments for ExternBlock {}
 impl ExternBlock {
-    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
     pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
     pub fn extern_item_list(&self) -> Option<ExternItemList> { support::child(&self.syntax) }
+    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -282,14 +313,36 @@ pub struct ExternCrate {
     pub(crate) syntax: SyntaxNode,
 }
 impl ast::HasAttrs for ExternCrate {}
-impl ast::HasVisibility for ExternCrate {}
 impl ast::HasDocComments for ExternCrate {}
+impl ast::HasVisibility for ExternCrate {}
 impl ExternCrate {
-    pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
-    pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
     pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
     pub fn rename(&self) -> Option<Rename> { support::child(&self.syntax) }
     pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+    pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
+    pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExternItemList {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasAttrs for ExternItemList {}
+impl ExternItemList {
+    pub fn extern_items(&self) -> AstChildren<ExternItem> { support::children(&self.syntax) }
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FieldExpr {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasAttrs for FieldExpr {}
+impl FieldExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
+    pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -297,769 +350,659 @@ pub struct Fn {
     pub(crate) syntax: SyntaxNode,
 }
 impl ast::HasAttrs for Fn {}
+impl ast::HasDocComments for Fn {}
+impl ast::HasGenericParams for Fn {}
 impl ast::HasName for Fn {}
 impl ast::HasVisibility for Fn {}
-impl ast::HasGenericParams for Fn {}
-impl ast::HasDocComments for Fn {}
 impl Fn {
-    pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
-    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
-    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
-    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
     pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
-    pub fn fn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![fn]) }
+    pub fn body(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
     pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
     pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
-    pub fn body(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
     pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Impl {
-    pub(crate) syntax: SyntaxNode,
-}
-impl ast::HasAttrs for Impl {}
-impl ast::HasVisibility for Impl {}
-impl ast::HasGenericParams for Impl {}
-impl ast::HasDocComments for Impl {}
-impl Impl {
+    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
+    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
     pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
+    pub fn fn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![fn]) }
     pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
-    pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) }
-    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
-    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
-    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
-    pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MacroRules {
+pub struct FnPtrType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MacroRules {}
-impl ast::HasName for MacroRules {}
-impl ast::HasVisibility for MacroRules {}
-impl ast::HasDocComments for MacroRules {}
-impl MacroRules {
-    pub fn macro_rules_token(&self) -> Option<SyntaxToken> {
-        support::token(&self.syntax, T![macro_rules])
-    }
-    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
-    pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
+impl FnPtrType {
+    pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
+    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
+    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
+    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
+    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
+    pub fn fn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![fn]) }
+    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MacroDef {
+pub struct ForExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MacroDef {}
-impl ast::HasName for MacroDef {}
-impl ast::HasVisibility for MacroDef {}
-impl ast::HasDocComments for MacroDef {}
-impl MacroDef {
-    pub fn macro_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![macro]) }
-    pub fn args(&self) -> Option<TokenTree> { support::child(&self.syntax) }
-    pub fn body(&self) -> Option<TokenTree> { support::child(&self.syntax) }
+impl ast::HasAttrs for ForExpr {}
+impl ForExpr {
+    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
+    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
+    pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Module {
+pub struct ForType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Module {}
-impl ast::HasName for Module {}
-impl ast::HasVisibility for Module {}
-impl ast::HasDocComments for Module {}
-impl Module {
-    pub fn mod_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mod]) }
-    pub fn item_list(&self) -> Option<ItemList> { support::child(&self.syntax) }
-    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+impl ForType {
+    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Static {
+pub struct FormatArgsArg {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Static {}
-impl ast::HasName for Static {}
-impl ast::HasVisibility for Static {}
-impl ast::HasDocComments for Static {}
-impl Static {
-    pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) }
-    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
-    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+impl ast::HasName for FormatArgsArg {}
+impl FormatArgsArg {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Struct {
+pub struct FormatArgsExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Struct {}
-impl ast::HasName for Struct {}
-impl ast::HasVisibility for Struct {}
-impl ast::HasGenericParams for Struct {}
-impl ast::HasDocComments for Struct {}
-impl Struct {
-    pub fn struct_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![struct]) }
-    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
-    pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) }
+impl ast::HasAttrs for FormatArgsExpr {}
+impl FormatArgsExpr {
+    pub fn args(&self) -> AstChildren<FormatArgsArg> { support::children(&self.syntax) }
+    pub fn template(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
+    pub fn format_args_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![format_args])
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Trait {
+pub struct GenericArgList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Trait {}
-impl ast::HasName for Trait {}
-impl ast::HasVisibility for Trait {}
-impl ast::HasGenericParams for Trait {}
-impl ast::HasTypeBounds for Trait {}
-impl ast::HasDocComments for Trait {}
-impl Trait {
-    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
-    pub fn auto_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![auto]) }
-    pub fn trait_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![trait]) }
-    pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
+impl GenericArgList {
+    pub fn generic_args(&self) -> AstChildren<GenericArg> { support::children(&self.syntax) }
+    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
+    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
+    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TraitAlias {
+pub struct GenericParamList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for TraitAlias {}
-impl ast::HasName for TraitAlias {}
-impl ast::HasVisibility for TraitAlias {}
-impl ast::HasGenericParams for TraitAlias {}
-impl ast::HasDocComments for TraitAlias {}
-impl TraitAlias {
-    pub fn trait_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![trait]) }
-    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) }
-    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+impl GenericParamList {
+    pub fn generic_params(&self) -> AstChildren<GenericParam> { support::children(&self.syntax) }
+    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
+    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TypeAlias {
+pub struct IdentPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for TypeAlias {}
-impl ast::HasName for TypeAlias {}
-impl ast::HasVisibility for TypeAlias {}
-impl ast::HasGenericParams for TypeAlias {}
-impl ast::HasTypeBounds for TypeAlias {}
-impl ast::HasDocComments for TypeAlias {}
-impl TypeAlias {
-    pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
-    pub fn type_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![type]) }
-    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+impl ast::HasAttrs for IdentPat {}
+impl ast::HasName for IdentPat {}
+impl IdentPat {
+    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
+    pub fn at_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![@]) }
+    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
+    pub fn ref_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ref]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Union {
+pub struct IfExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Union {}
-impl ast::HasName for Union {}
-impl ast::HasVisibility for Union {}
-impl ast::HasGenericParams for Union {}
-impl ast::HasDocComments for Union {}
-impl Union {
-    pub fn union_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![union]) }
-    pub fn record_field_list(&self) -> Option<RecordFieldList> { support::child(&self.syntax) }
+impl ast::HasAttrs for IfExpr {}
+impl IfExpr {
+    pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
+    pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Use {
+pub struct Impl {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Use {}
-impl ast::HasVisibility for Use {}
-impl ast::HasDocComments for Use {}
-impl Use {
-    pub fn use_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![use]) }
-    pub fn use_tree(&self) -> Option<UseTree> { support::child(&self.syntax) }
-    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+impl ast::HasAttrs for Impl {}
+impl ast::HasDocComments for Impl {}
+impl ast::HasGenericParams for Impl {}
+impl ast::HasVisibility for Impl {}
+impl Impl {
+    pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
+    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
+    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
+    pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
+    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
+    pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) }
+    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Visibility {
+pub struct ImplTraitType {
     pub(crate) syntax: SyntaxNode,
 }
-impl Visibility {
-    pub fn pub_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![pub]) }
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
-    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+impl ImplTraitType {
+    pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) }
+    pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ItemList {
+pub struct IndexExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ItemList {}
-impl ast::HasModuleItem for ItemList {}
-impl ItemList {
-    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+impl ast::HasAttrs for IndexExpr {}
+impl IndexExpr {
+    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Rename {
+pub struct InferType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasName for Rename {}
-impl Rename {
-    pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
+impl InferType {
     pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct UseTree {
-    pub(crate) syntax: SyntaxNode,
-}
-impl UseTree {
-    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
-    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
-    pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
-    pub fn use_tree_list(&self) -> Option<UseTreeList> { support::child(&self.syntax) }
-    pub fn rename(&self) -> Option<Rename> { support::child(&self.syntax) }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct UseTreeList {
+pub struct ItemList {
     pub(crate) syntax: SyntaxNode,
 }
-impl UseTreeList {
+impl ast::HasAttrs for ItemList {}
+impl ast::HasModuleItem for ItemList {}
+impl ItemList {
     pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn use_trees(&self) -> AstChildren<UseTree> { support::children(&self.syntax) }
     pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Abi {
-    pub(crate) syntax: SyntaxNode,
-}
-impl Abi {
-    pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericParamList {
+pub struct Label {
     pub(crate) syntax: SyntaxNode,
 }
-impl GenericParamList {
-    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
-    pub fn generic_params(&self) -> AstChildren<GenericParam> { support::children(&self.syntax) }
-    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
+impl Label {
+    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
+    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct WhereClause {
+pub struct LetElse {
     pub(crate) syntax: SyntaxNode,
 }
-impl WhereClause {
-    pub fn where_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![where]) }
-    pub fn predicates(&self) -> AstChildren<WherePred> { support::children(&self.syntax) }
+impl LetElse {
+    pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
+    pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct BlockExpr {
+pub struct LetExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for BlockExpr {}
-impl BlockExpr {
-    pub fn label(&self) -> Option<Label> { support::child(&self.syntax) }
-    pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) }
-    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
-    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
-    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
-    pub fn stmt_list(&self) -> Option<StmtList> { support::child(&self.syntax) }
+impl ast::HasAttrs for LetExpr {}
+impl LetExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct SelfParam {
+pub struct LetStmt {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for SelfParam {}
-impl ast::HasName for SelfParam {}
-impl SelfParam {
-    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
-    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
-    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
-    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+impl ast::HasAttrs for LetStmt {}
+impl LetStmt {
+    pub fn initializer(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn let_else(&self) -> Option<LetElse> { support::child(&self.syntax) }
+    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Param {
+pub struct Lifetime {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Param {}
-impl Param {
-    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
-    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    pub fn dotdotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![...]) }
+impl Lifetime {
+    pub fn lifetime_ident_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![lifetime_ident])
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RecordFieldList {
+pub struct LifetimeArg {
     pub(crate) syntax: SyntaxNode,
 }
-impl RecordFieldList {
-    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn fields(&self) -> AstChildren<RecordField> { support::children(&self.syntax) }
-    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+impl LifetimeArg {
+    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TupleFieldList {
+pub struct LifetimeParam {
     pub(crate) syntax: SyntaxNode,
 }
-impl TupleFieldList {
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn fields(&self) -> AstChildren<TupleField> { support::children(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+impl ast::HasAttrs for LifetimeParam {}
+impl ast::HasTypeBounds for LifetimeParam {}
+impl LifetimeParam {
+    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RecordField {
+pub struct Literal {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RecordField {}
-impl ast::HasName for RecordField {}
-impl ast::HasVisibility for RecordField {}
-impl ast::HasDocComments for RecordField {}
-impl RecordField {
-    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-}
+impl ast::HasAttrs for Literal {}
+impl Literal {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TupleField {
+pub struct LiteralPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for TupleField {}
-impl ast::HasVisibility for TupleField {}
-impl ast::HasDocComments for TupleField {}
-impl TupleField {
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+impl LiteralPat {
+    pub fn literal(&self) -> Option<Literal> { support::child(&self.syntax) }
+    pub fn minus_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![-]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct VariantList {
+pub struct LoopExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl VariantList {
-    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn variants(&self) -> AstChildren<Variant> { support::children(&self.syntax) }
-    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+impl ast::HasAttrs for LoopExpr {}
+impl ast::HasLoopBody for LoopExpr {}
+impl LoopExpr {
+    pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Variant {
+pub struct MacroCall {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Variant {}
-impl ast::HasName for Variant {}
-impl ast::HasVisibility for Variant {}
-impl ast::HasDocComments for Variant {}
-impl Variant {
-    pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) }
-    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+impl ast::HasAttrs for MacroCall {}
+impl ast::HasDocComments for MacroCall {}
+impl MacroCall {
+    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
+    pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
+    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AssocItemList {
+pub struct MacroDef {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for AssocItemList {}
-impl AssocItemList {
-    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn assoc_items(&self) -> AstChildren<AssocItem> { support::children(&self.syntax) }
-    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+impl ast::HasAttrs for MacroDef {}
+impl ast::HasDocComments for MacroDef {}
+impl ast::HasName for MacroDef {}
+impl ast::HasVisibility for MacroDef {}
+impl MacroDef {
+    pub fn args(&self) -> Option<TokenTree> { support::child(&self.syntax) }
+    pub fn body(&self) -> Option<TokenTree> { support::child(&self.syntax) }
+    pub fn macro_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![macro]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ExternItemList {
+pub struct MacroEagerInput {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ExternItemList {}
-impl ExternItemList {
+impl MacroEagerInput {
+    pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
     pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn extern_items(&self) -> AstChildren<ExternItem> { support::children(&self.syntax) }
     pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ConstParam {
+pub struct MacroExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ConstParam {}
-impl ast::HasName for ConstParam {}
-impl ConstParam {
-    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
-    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn default_val(&self) -> Option<ConstArg> { support::child(&self.syntax) }
+impl MacroExpr {
+    pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct LifetimeParam {
+pub struct MacroItems {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for LifetimeParam {}
-impl ast::HasTypeBounds for LifetimeParam {}
-impl LifetimeParam {
-    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
-}
+impl ast::HasModuleItem for MacroItems {}
+impl MacroItems {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TypeParam {
+pub struct MacroPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for TypeParam {}
-impl ast::HasName for TypeParam {}
-impl ast::HasTypeBounds for TypeParam {}
-impl TypeParam {
-    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn default_type(&self) -> Option<Type> { support::child(&self.syntax) }
+impl MacroPat {
+    pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct WherePred {
+pub struct MacroRules {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasTypeBounds for WherePred {}
-impl WherePred {
-    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
-    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
-    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+impl ast::HasAttrs for MacroRules {}
+impl ast::HasDocComments for MacroRules {}
+impl ast::HasName for MacroRules {}
+impl ast::HasVisibility for MacroRules {}
+impl MacroRules {
+    pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
+    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
+    pub fn macro_rules_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![macro_rules])
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Meta {
+pub struct MacroStmts {
     pub(crate) syntax: SyntaxNode,
 }
-impl Meta {
-    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
-    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+impl MacroStmts {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
+    pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ExprStmt {
+pub struct MacroType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ExprStmt {
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+impl MacroType {
+    pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct LetStmt {
+pub struct MatchArm {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for LetStmt {}
-impl LetStmt {
-    pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
+impl ast::HasAttrs for MatchArm {}
+impl MatchArm {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn guard(&self) -> Option<MatchGuard> { support::child(&self.syntax) }
     pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
-    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn initializer(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn let_else(&self) -> Option<LetElse> { support::child(&self.syntax) }
-    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+    pub fn fat_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=>]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct LetElse {
+pub struct MatchArmList {
     pub(crate) syntax: SyntaxNode,
 }
-impl LetElse {
-    pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
-    pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
+impl ast::HasAttrs for MatchArmList {}
+impl MatchArmList {
+    pub fn arms(&self) -> AstChildren<MatchArm> { support::children(&self.syntax) }
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ArrayExpr {
+pub struct MatchExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ArrayExpr {}
-impl ArrayExpr {
-    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
-    pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
+impl ast::HasAttrs for MatchExpr {}
+impl MatchExpr {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
-    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+    pub fn match_arm_list(&self) -> Option<MatchArmList> { support::child(&self.syntax) }
+    pub fn match_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![match]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AsmExpr {
+pub struct MatchGuard {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for AsmExpr {}
-impl AsmExpr {
-    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
-    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
-    pub fn asm_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![asm]) }
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+impl MatchGuard {
+    pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AwaitExpr {
+pub struct Meta {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for AwaitExpr {}
-impl AwaitExpr {
+impl Meta {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
-    pub fn await_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![await]) }
+    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
+    pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct BinExpr {
+pub struct MethodCallExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for BinExpr {}
-impl BinExpr {}
+impl ast::HasArgList for MethodCallExpr {}
+impl ast::HasAttrs for MethodCallExpr {}
+impl MethodCallExpr {
+    pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) }
+    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
+    pub fn receiver(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
+}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct BreakExpr {
+pub struct Module {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for BreakExpr {}
-impl BreakExpr {
-    pub fn break_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![break]) }
-    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+impl ast::HasAttrs for Module {}
+impl ast::HasDocComments for Module {}
+impl ast::HasName for Module {}
+impl ast::HasVisibility for Module {}
+impl Module {
+    pub fn item_list(&self) -> Option<ItemList> { support::child(&self.syntax) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+    pub fn mod_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mod]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct CallExpr {
+pub struct Name {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for CallExpr {}
-impl ast::HasArgList for CallExpr {}
-impl CallExpr {
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+impl Name {
+    pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) }
+    pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct CastExpr {
+pub struct NameRef {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for CastExpr {}
-impl CastExpr {
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+impl NameRef {
+    pub fn Self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![Self]) }
+    pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
+    pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) }
+    pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
+    pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ClosureExpr {
+pub struct NeverType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ClosureExpr {}
-impl ClosureExpr {
-    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
-    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
-    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
-    pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) }
-    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
-    pub fn move_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![move]) }
-    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
-    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
-    pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
+impl NeverType {
+    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ContinueExpr {
+pub struct OffsetOfExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ContinueExpr {}
-impl ContinueExpr {
-    pub fn continue_token(&self) -> Option<SyntaxToken> {
-        support::token(&self.syntax, T![continue])
+impl ast::HasAttrs for OffsetOfExpr {}
+impl OffsetOfExpr {
+    pub fn fields(&self) -> AstChildren<NameRef> { support::children(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
+    pub fn offset_of_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![offset_of])
     }
-    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct FieldExpr {
+pub struct OrPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for FieldExpr {}
-impl FieldExpr {
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
-    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
+impl OrPat {
+    pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ForExpr {
+pub struct Param {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ForExpr {}
-impl ForExpr {
-    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
+impl ast::HasAttrs for Param {}
+impl Param {
     pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
-    pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn dotdotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![...]) }
+    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct FormatArgsExpr {
+pub struct ParamList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for FormatArgsExpr {}
-impl FormatArgsExpr {
-    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
-    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
-    pub fn format_args_token(&self) -> Option<SyntaxToken> {
-        support::token(&self.syntax, T![format_args])
-    }
+impl ParamList {
+    pub fn params(&self) -> AstChildren<Param> { support::children(&self.syntax) }
+    pub fn self_param(&self) -> Option<SelfParam> { support::child(&self.syntax) }
     pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn template(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
-    pub fn args(&self) -> AstChildren<FormatArgsArg> { support::children(&self.syntax) }
     pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+    pub fn pipe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![|]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct IfExpr {
+pub struct ParenExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for IfExpr {}
-impl IfExpr {
-    pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
-    pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
+impl ast::HasAttrs for ParenExpr {}
+impl ParenExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct IndexExpr {
+pub struct ParenPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for IndexExpr {}
-impl IndexExpr {
-    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
-    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+impl ParenPat {
+    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Literal {
+pub struct ParenType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Literal {}
-impl Literal {}
+impl ParenType {
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct LoopExpr {
+pub struct Path {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for LoopExpr {}
-impl ast::HasLoopBody for LoopExpr {}
-impl LoopExpr {
-    pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) }
+impl Path {
+    pub fn qualifier(&self) -> Option<Path> { support::child(&self.syntax) }
+    pub fn segment(&self) -> Option<PathSegment> { support::child(&self.syntax) }
+    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MacroExpr {
+pub struct PathExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl MacroExpr {
-    pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) }
+impl ast::HasAttrs for PathExpr {}
+impl PathExpr {
+    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MatchExpr {
+pub struct PathPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MatchExpr {}
-impl MatchExpr {
-    pub fn match_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![match]) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn match_arm_list(&self) -> Option<MatchArmList> { support::child(&self.syntax) }
+impl PathPat {
+    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MethodCallExpr {
+pub struct PathSegment {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MethodCallExpr {}
-impl ast::HasArgList for MethodCallExpr {}
-impl MethodCallExpr {
-    pub fn receiver(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
-    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
+impl PathSegment {
     pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) }
+    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
+    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
+    pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) }
+    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
+    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
+    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
+    pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct OffsetOfExpr {
+pub struct PathType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for OffsetOfExpr {}
-impl OffsetOfExpr {
-    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
-    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
-    pub fn offset_of_token(&self) -> Option<SyntaxToken> {
-        support::token(&self.syntax, T![offset_of])
-    }
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
-    pub fn fields(&self) -> AstChildren<NameRef> { support::children(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+impl PathType {
+    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ParenExpr {
+pub struct PrefixExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ParenExpr {}
-impl ParenExpr {
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+impl ast::HasAttrs for PrefixExpr {}
+impl PrefixExpr {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct PathExpr {
+pub struct PtrType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for PathExpr {}
-impl PathExpr {
-    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
+impl PtrType {
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
+    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
+    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct PrefixExpr {
+pub struct RangeExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for PrefixExpr {}
-impl PrefixExpr {
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-}
+impl ast::HasAttrs for RangeExpr {}
+impl RangeExpr {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RangeExpr {
+pub struct RangePat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RangeExpr {}
-impl RangeExpr {}
+impl RangePat {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct RecordExpr {
@@ -1073,325 +1016,354 @@ impl RecordExpr {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RefExpr {
+pub struct RecordExprField {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RefExpr {}
-impl RefExpr {
-    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
-    pub fn raw_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![raw]) }
-    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
-    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
+impl ast::HasAttrs for RecordExprField {}
+impl RecordExprField {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
+    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ReturnExpr {
+pub struct RecordExprFieldList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ReturnExpr {}
-impl ReturnExpr {
-    pub fn return_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![return]) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+impl ast::HasAttrs for RecordExprFieldList {}
+impl RecordExprFieldList {
+    pub fn fields(&self) -> AstChildren<RecordExprField> { support::children(&self.syntax) }
+    pub fn spread(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+    pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct BecomeExpr {
+pub struct RecordField {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for BecomeExpr {}
-impl BecomeExpr {
-    pub fn become_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![become]) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+impl ast::HasAttrs for RecordField {}
+impl ast::HasDocComments for RecordField {}
+impl ast::HasName for RecordField {}
+impl ast::HasVisibility for RecordField {}
+impl RecordField {
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TryExpr {
+pub struct RecordFieldList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for TryExpr {}
-impl TryExpr {
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
+impl RecordFieldList {
+    pub fn fields(&self) -> AstChildren<RecordField> { support::children(&self.syntax) }
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TupleExpr {
+pub struct RecordPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for TupleExpr {}
-impl TupleExpr {
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn fields(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+impl RecordPat {
+    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
+    pub fn record_pat_field_list(&self) -> Option<RecordPatFieldList> {
+        support::child(&self.syntax)
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct WhileExpr {
+pub struct RecordPatField {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for WhileExpr {}
-impl WhileExpr {
-    pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
+impl ast::HasAttrs for RecordPatField {}
+impl RecordPatField {
+    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
+    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
+    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct YieldExpr {
+pub struct RecordPatFieldList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for YieldExpr {}
-impl YieldExpr {
-    pub fn yield_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![yield]) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+impl RecordPatFieldList {
+    pub fn fields(&self) -> AstChildren<RecordPatField> { support::children(&self.syntax) }
+    pub fn rest_pat(&self) -> Option<RestPat> { support::child(&self.syntax) }
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct YeetExpr {
+pub struct RefExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for YeetExpr {}
-impl YeetExpr {
-    pub fn do_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![do]) }
-    pub fn yeet_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![yeet]) }
+impl ast::HasAttrs for RefExpr {}
+impl RefExpr {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
+    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
+    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
+    pub fn raw_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![raw]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct LetExpr {
+pub struct RefPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for LetExpr {}
-impl LetExpr {
-    pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
+impl RefPat {
     pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
-    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct UnderscoreExpr {
-    pub(crate) syntax: SyntaxNode,
-}
-impl ast::HasAttrs for UnderscoreExpr {}
-impl UnderscoreExpr {
-    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
+    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
+    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct FormatArgsArg {
+pub struct RefType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasName for FormatArgsArg {}
-impl FormatArgsArg {
-    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+impl RefType {
+    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
+    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct StmtList {
+pub struct Rename {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for StmtList {}
-impl StmtList {
-    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
-    pub fn tail_expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+impl ast::HasName for Rename {}
+impl Rename {
+    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
+    pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Label {
+pub struct RestPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl Label {
-    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
-    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+impl ast::HasAttrs for RestPat {}
+impl RestPat {
+    pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RecordExprFieldList {
+pub struct RetType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RecordExprFieldList {}
-impl RecordExprFieldList {
-    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn fields(&self) -> AstChildren<RecordExprField> { support::children(&self.syntax) }
-    pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
-    pub fn spread(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+impl RetType {
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn thin_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![->]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RecordExprField {
+pub struct ReturnExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RecordExprField {}
-impl RecordExprField {
-    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
-    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+impl ast::HasAttrs for ReturnExpr {}
+impl ReturnExpr {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn return_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![return]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ArgList {
+pub struct SelfParam {
     pub(crate) syntax: SyntaxNode,
 }
-impl ArgList {
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn args(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+impl ast::HasAttrs for SelfParam {}
+impl ast::HasName for SelfParam {}
+impl SelfParam {
+    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
+    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MatchArmList {
+pub struct SlicePat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MatchArmList {}
-impl MatchArmList {
-    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn arms(&self) -> AstChildren<MatchArm> { support::children(&self.syntax) }
-    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+impl SlicePat {
+    pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
+    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MatchArm {
+pub struct SliceType {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MatchArm {}
-impl MatchArm {
-    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
-    pub fn guard(&self) -> Option<MatchGuard> { support::child(&self.syntax) }
-    pub fn fat_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=>]) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+impl SliceType {
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MatchGuard {
+pub struct SourceFile {
     pub(crate) syntax: SyntaxNode,
 }
-impl MatchGuard {
-    pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
+impl ast::HasAttrs for SourceFile {}
+impl ast::HasDocComments for SourceFile {}
+impl ast::HasModuleItem for SourceFile {}
+impl SourceFile {
+    pub fn shebang_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![shebang]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ArrayType {
+pub struct Static {
     pub(crate) syntax: SyntaxNode,
 }
-impl ArrayType {
-    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+impl ast::HasAttrs for Static {}
+impl ast::HasDocComments for Static {}
+impl ast::HasName for Static {}
+impl ast::HasVisibility for Static {}
+impl Static {
+    pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
     pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
-    pub fn const_arg(&self) -> Option<ConstArg> { support::child(&self.syntax) }
-    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
+    pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct DynTraitType {
+pub struct StmtList {
     pub(crate) syntax: SyntaxNode,
 }
-impl DynTraitType {
-    pub fn dyn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![dyn]) }
-    pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) }
+impl ast::HasAttrs for StmtList {}
+impl StmtList {
+    pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
+    pub fn tail_expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct FnPtrType {
+pub struct Struct {
     pub(crate) syntax: SyntaxNode,
 }
-impl FnPtrType {
-    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
-    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
-    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
-    pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
-    pub fn fn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![fn]) }
-    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
-    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
+impl ast::HasAttrs for Struct {}
+impl ast::HasDocComments for Struct {}
+impl ast::HasGenericParams for Struct {}
+impl ast::HasName for Struct {}
+impl ast::HasVisibility for Struct {}
+impl Struct {
+    pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+    pub fn struct_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![struct]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ForType {
+pub struct TokenTree {
     pub(crate) syntax: SyntaxNode,
 }
-impl ForType {
-    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
-    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+impl TokenTree {
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ImplTraitType {
+pub struct Trait {
     pub(crate) syntax: SyntaxNode,
 }
-impl ImplTraitType {
-    pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) }
-    pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) }
+impl ast::HasAttrs for Trait {}
+impl ast::HasDocComments for Trait {}
+impl ast::HasGenericParams for Trait {}
+impl ast::HasName for Trait {}
+impl ast::HasTypeBounds for Trait {}
+impl ast::HasVisibility for Trait {}
+impl Trait {
+    pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
+    pub fn auto_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![auto]) }
+    pub fn trait_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![trait]) }
+    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct InferType {
+pub struct TraitAlias {
     pub(crate) syntax: SyntaxNode,
 }
-impl InferType {
-    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
+impl ast::HasAttrs for TraitAlias {}
+impl ast::HasDocComments for TraitAlias {}
+impl ast::HasGenericParams for TraitAlias {}
+impl ast::HasName for TraitAlias {}
+impl ast::HasVisibility for TraitAlias {}
+impl TraitAlias {
+    pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn trait_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![trait]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MacroType {
+pub struct TryExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl MacroType {
-    pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) }
+impl ast::HasAttrs for TryExpr {}
+impl TryExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct NeverType {
+pub struct TupleExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl NeverType {
-    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
+impl ast::HasAttrs for TupleExpr {}
+impl TupleExpr {
+    pub fn fields(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ParenType {
+pub struct TupleField {
     pub(crate) syntax: SyntaxNode,
 }
-impl ParenType {
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+impl ast::HasAttrs for TupleField {}
+impl ast::HasDocComments for TupleField {}
+impl ast::HasVisibility for TupleField {}
+impl TupleField {
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct PtrType {
+pub struct TupleFieldList {
     pub(crate) syntax: SyntaxNode,
 }
-impl PtrType {
-    pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
-    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
-    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+impl TupleFieldList {
+    pub fn fields(&self) -> AstChildren<TupleField> { support::children(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RefType {
+pub struct TuplePat {
     pub(crate) syntax: SyntaxNode,
 }
-impl RefType {
-    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
-    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
-    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+impl TuplePat {
+    pub fn fields(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct SliceType {
+pub struct TupleStructPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl SliceType {
-    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+impl TupleStructPat {
+    pub fn fields(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
+    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -1399,226 +1371,251 @@ pub struct TupleType {
     pub(crate) syntax: SyntaxNode,
 }
 impl TupleType {
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
     pub fn fields(&self) -> AstChildren<Type> { support::children(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
     pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TypeBound {
+pub struct TypeAlias {
     pub(crate) syntax: SyntaxNode,
 }
-impl TypeBound {
-    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
-    pub fn tilde_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![~]) }
-    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
-    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
-    pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
+impl ast::HasAttrs for TypeAlias {}
+impl ast::HasDocComments for TypeAlias {}
+impl ast::HasGenericParams for TypeAlias {}
+impl ast::HasName for TypeAlias {}
+impl ast::HasTypeBounds for TypeAlias {}
+impl ast::HasVisibility for TypeAlias {}
+impl TypeAlias {
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
+    pub fn type_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![type]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct IdentPat {
+pub struct TypeArg {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for IdentPat {}
-impl ast::HasName for IdentPat {}
-impl IdentPat {
-    pub fn ref_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ref]) }
-    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
-    pub fn at_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![@]) }
-    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
+impl TypeArg {
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct BoxPat {
+pub struct TypeBound {
     pub(crate) syntax: SyntaxNode,
 }
-impl BoxPat {
-    pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) }
-    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
+impl TypeBound {
+    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
+    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
+    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
+    pub fn tilde_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![~]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RestPat {
+pub struct TypeBoundList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RestPat {}
-impl RestPat {
-    pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
+impl TypeBoundList {
+    pub fn bounds(&self) -> AstChildren<TypeBound> { support::children(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct LiteralPat {
+pub struct TypeParam {
     pub(crate) syntax: SyntaxNode,
 }
-impl LiteralPat {
-    pub fn minus_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![-]) }
-    pub fn literal(&self) -> Option<Literal> { support::child(&self.syntax) }
+impl ast::HasAttrs for TypeParam {}
+impl ast::HasName for TypeParam {}
+impl ast::HasTypeBounds for TypeParam {}
+impl TypeParam {
+    pub fn default_type(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MacroPat {
+pub struct UnderscoreExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl MacroPat {
-    pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) }
+impl ast::HasAttrs for UnderscoreExpr {}
+impl UnderscoreExpr {
+    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct OrPat {
+pub struct Union {
     pub(crate) syntax: SyntaxNode,
 }
-impl OrPat {
-    pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
+impl ast::HasAttrs for Union {}
+impl ast::HasDocComments for Union {}
+impl ast::HasGenericParams for Union {}
+impl ast::HasName for Union {}
+impl ast::HasVisibility for Union {}
+impl Union {
+    pub fn record_field_list(&self) -> Option<RecordFieldList> { support::child(&self.syntax) }
+    pub fn union_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![union]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ParenPat {
+pub struct Use {
     pub(crate) syntax: SyntaxNode,
 }
-impl ParenPat {
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+impl ast::HasAttrs for Use {}
+impl ast::HasDocComments for Use {}
+impl ast::HasVisibility for Use {}
+impl Use {
+    pub fn use_tree(&self) -> Option<UseTree> { support::child(&self.syntax) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+    pub fn use_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![use]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct PathPat {
+pub struct UseTree {
     pub(crate) syntax: SyntaxNode,
 }
-impl PathPat {
+impl UseTree {
     pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
+    pub fn rename(&self) -> Option<Rename> { support::child(&self.syntax) }
+    pub fn use_tree_list(&self) -> Option<UseTreeList> { support::child(&self.syntax) }
+    pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
+    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct WildcardPat {
+pub struct UseTreeList {
     pub(crate) syntax: SyntaxNode,
 }
-impl WildcardPat {
-    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
+impl UseTreeList {
+    pub fn use_trees(&self) -> AstChildren<UseTree> { support::children(&self.syntax) }
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RangePat {
+pub struct Variant {
     pub(crate) syntax: SyntaxNode,
 }
-impl RangePat {}
+impl ast::HasAttrs for Variant {}
+impl ast::HasDocComments for Variant {}
+impl ast::HasName for Variant {}
+impl ast::HasVisibility for Variant {}
+impl Variant {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RecordPat {
+pub struct VariantList {
     pub(crate) syntax: SyntaxNode,
 }
-impl RecordPat {
-    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
-    pub fn record_pat_field_list(&self) -> Option<RecordPatFieldList> {
-        support::child(&self.syntax)
-    }
+impl VariantList {
+    pub fn variants(&self) -> AstChildren<Variant> { support::children(&self.syntax) }
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RefPat {
+pub struct Visibility {
     pub(crate) syntax: SyntaxNode,
 }
-impl RefPat {
-    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
-    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
-    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
+impl Visibility {
+    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+    pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
+    pub fn pub_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![pub]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct SlicePat {
+pub struct WhereClause {
     pub(crate) syntax: SyntaxNode,
 }
-impl SlicePat {
-    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
-    pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
-    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+impl WhereClause {
+    pub fn predicates(&self) -> AstChildren<WherePred> { support::children(&self.syntax) }
+    pub fn where_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![where]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TuplePat {
+pub struct WherePred {
     pub(crate) syntax: SyntaxNode,
 }
-impl TuplePat {
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn fields(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+impl ast::HasTypeBounds for WherePred {}
+impl WherePred {
+    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
+    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TupleStructPat {
+pub struct WhileExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl TupleStructPat {
-    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
-    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
-    pub fn fields(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
-    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+impl ast::HasAttrs for WhileExpr {}
+impl WhileExpr {
+    pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ConstBlockPat {
+pub struct WildcardPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ConstBlockPat {
-    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
-    pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
+impl WildcardPat {
+    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RecordPatFieldList {
+pub struct YeetExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl RecordPatFieldList {
-    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
-    pub fn fields(&self) -> AstChildren<RecordPatField> { support::children(&self.syntax) }
-    pub fn rest_pat(&self) -> Option<RestPat> { support::child(&self.syntax) }
-    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+impl ast::HasAttrs for YeetExpr {}
+impl YeetExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn do_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![do]) }
+    pub fn yeet_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![yeet]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RecordPatField {
+pub struct YieldExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RecordPatField {}
-impl RecordPatField {
-    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
-    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
-    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
+impl ast::HasAttrs for YieldExpr {}
+impl YieldExpr {
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn yield_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![yield]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum Type {
-    ArrayType(ArrayType),
-    DynTraitType(DynTraitType),
-    FnPtrType(FnPtrType),
-    ForType(ForType),
-    ImplTraitType(ImplTraitType),
-    InferType(InferType),
-    MacroType(MacroType),
-    NeverType(NeverType),
-    ParenType(ParenType),
-    PathType(PathType),
-    PtrType(PtrType),
-    RefType(RefType),
-    SliceType(SliceType),
-    TupleType(TupleType),
+pub enum Adt {
+    Enum(Enum),
+    Struct(Struct),
+    Union(Union),
 }
+impl ast::HasAttrs for Adt {}
+impl ast::HasDocComments for Adt {}
+impl ast::HasGenericParams for Adt {}
+impl ast::HasName for Adt {}
+impl ast::HasVisibility for Adt {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum GenericArg {
-    TypeArg(TypeArg),
-    AssocTypeArg(AssocTypeArg),
-    LifetimeArg(LifetimeArg),
-    ConstArg(ConstArg),
+pub enum AssocItem {
+    Const(Const),
+    Fn(Fn),
+    MacroCall(MacroCall),
+    TypeAlias(TypeAlias),
 }
+impl ast::HasAttrs for AssocItem {}
+impl ast::HasDocComments for AssocItem {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Expr {
     ArrayExpr(ArrayExpr),
     AsmExpr(AsmExpr),
     AwaitExpr(AwaitExpr),
+    BecomeExpr(BecomeExpr),
     BinExpr(BinExpr),
     BlockExpr(BlockExpr),
     BreakExpr(BreakExpr),
@@ -1631,6 +1628,7 @@ pub enum Expr {
     FormatArgsExpr(FormatArgsExpr),
     IfExpr(IfExpr),
     IndexExpr(IndexExpr),
+    LetExpr(LetExpr),
     Literal(Literal),
     LoopExpr(LoopExpr),
     MacroExpr(MacroExpr),
@@ -1644,17 +1642,47 @@ pub enum Expr {
     RecordExpr(RecordExpr),
     RefExpr(RefExpr),
     ReturnExpr(ReturnExpr),
-    BecomeExpr(BecomeExpr),
     TryExpr(TryExpr),
     TupleExpr(TupleExpr),
+    UnderscoreExpr(UnderscoreExpr),
     WhileExpr(WhileExpr),
-    YieldExpr(YieldExpr),
     YeetExpr(YeetExpr),
-    LetExpr(LetExpr),
-    UnderscoreExpr(UnderscoreExpr),
+    YieldExpr(YieldExpr),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum ExternItem {
+    Fn(Fn),
+    MacroCall(MacroCall),
+    Static(Static),
+    TypeAlias(TypeAlias),
+}
+impl ast::HasAttrs for ExternItem {}
+impl ast::HasDocComments for ExternItem {}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum FieldList {
+    RecordFieldList(RecordFieldList),
+    TupleFieldList(TupleFieldList),
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum GenericArg {
+    AssocTypeArg(AssocTypeArg),
+    ConstArg(ConstArg),
+    LifetimeArg(LifetimeArg),
+    TypeArg(TypeArg),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum GenericParam {
+    ConstParam(ConstParam),
+    LifetimeParam(LifetimeParam),
+    TypeParam(TypeParam),
+}
+impl ast::HasAttrs for GenericParam {}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Item {
     Const(Const),
     Enum(Enum),
@@ -1663,8 +1691,8 @@ pub enum Item {
     Fn(Fn),
     Impl(Impl),
     MacroCall(MacroCall),
-    MacroRules(MacroRules),
     MacroDef(MacroDef),
+    MacroRules(MacroRules),
     Module(Module),
     Static(Static),
     Struct(Struct),
@@ -1678,77 +1706,49 @@ impl ast::HasAttrs for Item {}
 impl ast::HasDocComments for Item {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum Stmt {
-    ExprStmt(ExprStmt),
-    Item(Item),
-    LetStmt(LetStmt),
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Pat {
-    IdentPat(IdentPat),
     BoxPat(BoxPat),
-    RestPat(RestPat),
+    ConstBlockPat(ConstBlockPat),
+    IdentPat(IdentPat),
     LiteralPat(LiteralPat),
     MacroPat(MacroPat),
     OrPat(OrPat),
     ParenPat(ParenPat),
     PathPat(PathPat),
-    WildcardPat(WildcardPat),
     RangePat(RangePat),
     RecordPat(RecordPat),
     RefPat(RefPat),
+    RestPat(RestPat),
     SlicePat(SlicePat),
     TuplePat(TuplePat),
     TupleStructPat(TupleStructPat),
-    ConstBlockPat(ConstBlockPat),
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum FieldList {
-    RecordFieldList(RecordFieldList),
-    TupleFieldList(TupleFieldList),
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum Adt {
-    Enum(Enum),
-    Struct(Struct),
-    Union(Union),
+    WildcardPat(WildcardPat),
 }
-impl ast::HasAttrs for Adt {}
-impl ast::HasDocComments for Adt {}
-impl ast::HasGenericParams for Adt {}
-impl ast::HasName for Adt {}
-impl ast::HasVisibility for Adt {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum AssocItem {
-    Const(Const),
-    Fn(Fn),
-    MacroCall(MacroCall),
-    TypeAlias(TypeAlias),
-}
-impl ast::HasAttrs for AssocItem {}
-impl ast::HasDocComments for AssocItem {}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum ExternItem {
-    Fn(Fn),
-    MacroCall(MacroCall),
-    Static(Static),
-    TypeAlias(TypeAlias),
+pub enum Stmt {
+    ExprStmt(ExprStmt),
+    Item(Item),
+    LetStmt(LetStmt),
 }
-impl ast::HasAttrs for ExternItem {}
-impl ast::HasDocComments for ExternItem {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum GenericParam {
-    ConstParam(ConstParam),
-    LifetimeParam(LifetimeParam),
-    TypeParam(TypeParam),
+pub enum Type {
+    ArrayType(ArrayType),
+    DynTraitType(DynTraitType),
+    FnPtrType(FnPtrType),
+    ForType(ForType),
+    ImplTraitType(ImplTraitType),
+    InferType(InferType),
+    MacroType(MacroType),
+    NeverType(NeverType),
+    ParenType(ParenType),
+    PathType(PathType),
+    PtrType(PtrType),
+    RefType(RefType),
+    SliceType(SliceType),
+    TupleType(TupleType),
 }
-impl ast::HasAttrs for GenericParam {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct AnyHasArgList {
@@ -1803,8 +1803,8 @@ pub struct AnyHasVisibility {
     pub(crate) syntax: SyntaxNode,
 }
 impl ast::HasVisibility for AnyHasVisibility {}
-impl AstNode for Name {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == NAME }
+impl AstNode for Abi {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ABI }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1814,8 +1814,8 @@ impl AstNode for Name {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for NameRef {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == NAME_REF }
+impl AstNode for ArgList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ARG_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1825,8 +1825,8 @@ impl AstNode for NameRef {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Lifetime {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME }
+impl AstNode for ArrayExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1836,8 +1836,8 @@ impl AstNode for Lifetime {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Path {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH }
+impl AstNode for ArrayType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1847,8 +1847,8 @@ impl AstNode for Path {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for PathSegment {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_SEGMENT }
+impl AstNode for AsmExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1858,8 +1858,8 @@ impl AstNode for PathSegment {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for GenericArgList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_ARG_LIST }
+impl AstNode for AssocItemList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1869,8 +1869,8 @@ impl AstNode for GenericArgList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ParamList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST }
+impl AstNode for AssocTypeArg {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1880,8 +1880,8 @@ impl AstNode for ParamList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RetType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RET_TYPE }
+impl AstNode for Attr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ATTR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1891,8 +1891,8 @@ impl AstNode for RetType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for PathType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_TYPE }
+impl AstNode for AwaitExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1902,8 +1902,8 @@ impl AstNode for PathType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TypeArg {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG }
+impl AstNode for BecomeExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == BECOME_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1913,8 +1913,8 @@ impl AstNode for TypeArg {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for AssocTypeArg {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG }
+impl AstNode for BinExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1924,8 +1924,8 @@ impl AstNode for AssocTypeArg {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for LifetimeArg {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG }
+impl AstNode for BlockExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == BLOCK_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1935,8 +1935,8 @@ impl AstNode for LifetimeArg {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ConstArg {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_ARG }
+impl AstNode for BoxPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1946,8 +1946,8 @@ impl AstNode for ConstArg {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TypeBoundList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST }
+impl AstNode for BreakExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == BREAK_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1957,8 +1957,8 @@ impl AstNode for TypeBoundList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MacroCall {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_CALL }
+impl AstNode for CallExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == CALL_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1968,8 +1968,8 @@ impl AstNode for MacroCall {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Attr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == ATTR }
+impl AstNode for CastExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == CAST_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1979,8 +1979,8 @@ impl AstNode for Attr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TokenTree {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TOKEN_TREE }
+impl AstNode for ClosureExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == CLOSURE_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1990,8 +1990,8 @@ impl AstNode for TokenTree {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MacroItems {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_ITEMS }
+impl AstNode for Const {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2001,8 +2001,8 @@ impl AstNode for MacroItems {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MacroEagerInput {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EAGER_INPUT }
+impl AstNode for ConstArg {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_ARG }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2012,8 +2012,8 @@ impl AstNode for MacroEagerInput {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MacroStmts {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS }
+impl AstNode for ConstBlockPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_BLOCK_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2023,8 +2023,8 @@ impl AstNode for MacroStmts {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for SourceFile {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == SOURCE_FILE }
+impl AstNode for ConstParam {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_PARAM }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2034,8 +2034,8 @@ impl AstNode for SourceFile {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Const {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST }
+impl AstNode for ContinueExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == CONTINUE_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2045,8 +2045,8 @@ impl AstNode for Const {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Enum {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM }
+impl AstNode for DynTraitType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == DYN_TRAIT_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2056,8 +2056,8 @@ impl AstNode for Enum {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ExternBlock {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_BLOCK }
+impl AstNode for Enum {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2067,8 +2067,8 @@ impl AstNode for ExternBlock {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ExternCrate {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_CRATE }
+impl AstNode for ExprStmt {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2078,8 +2078,8 @@ impl AstNode for ExternCrate {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Fn {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == FN }
+impl AstNode for ExternBlock {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_BLOCK }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2089,8 +2089,8 @@ impl AstNode for Fn {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Impl {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL }
+impl AstNode for ExternCrate {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_CRATE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2100,8 +2100,8 @@ impl AstNode for Impl {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MacroRules {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_RULES }
+impl AstNode for ExternItemList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_ITEM_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2111,8 +2111,8 @@ impl AstNode for MacroRules {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MacroDef {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF }
+impl AstNode for FieldExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2122,8 +2122,8 @@ impl AstNode for MacroDef {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Module {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
+impl AstNode for Fn {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FN }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2133,8 +2133,8 @@ impl AstNode for Module {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Static {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == STATIC }
+impl AstNode for FnPtrType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FN_PTR_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2144,8 +2144,8 @@ impl AstNode for Static {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Struct {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == STRUCT }
+impl AstNode for ForExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2155,8 +2155,8 @@ impl AstNode for Struct {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Trait {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT }
+impl AstNode for ForType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2166,8 +2166,8 @@ impl AstNode for Trait {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TraitAlias {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT_ALIAS }
+impl AstNode for FormatArgsArg {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_ARG }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2177,8 +2177,8 @@ impl AstNode for TraitAlias {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TypeAlias {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ALIAS }
+impl AstNode for FormatArgsExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2188,8 +2188,8 @@ impl AstNode for TypeAlias {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Union {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == UNION }
+impl AstNode for GenericArgList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_ARG_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2199,8 +2199,8 @@ impl AstNode for Union {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Use {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == USE }
+impl AstNode for GenericParamList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2210,8 +2210,8 @@ impl AstNode for Use {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Visibility {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY }
+impl AstNode for IdentPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2221,8 +2221,8 @@ impl AstNode for Visibility {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ItemList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == ITEM_LIST }
+impl AstNode for IfExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2232,8 +2232,8 @@ impl AstNode for ItemList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Rename {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RENAME }
+impl AstNode for Impl {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2243,8 +2243,8 @@ impl AstNode for Rename {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for UseTree {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
+impl AstNode for ImplTraitType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_TRAIT_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2254,8 +2254,8 @@ impl AstNode for UseTree {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for UseTreeList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST }
+impl AstNode for IndexExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == INDEX_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2265,8 +2265,8 @@ impl AstNode for UseTreeList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Abi {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == ABI }
+impl AstNode for InferType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == INFER_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2276,8 +2276,8 @@ impl AstNode for Abi {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for GenericParamList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
+impl AstNode for ItemList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ITEM_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2287,8 +2287,8 @@ impl AstNode for GenericParamList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for WhereClause {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE }
+impl AstNode for Label {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2298,8 +2298,8 @@ impl AstNode for WhereClause {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for BlockExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == BLOCK_EXPR }
+impl AstNode for LetElse {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LET_ELSE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2309,8 +2309,8 @@ impl AstNode for BlockExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for SelfParam {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == SELF_PARAM }
+impl AstNode for LetExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LET_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2320,8 +2320,8 @@ impl AstNode for SelfParam {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Param {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM }
+impl AstNode for LetStmt {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LET_STMT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2331,8 +2331,8 @@ impl AstNode for Param {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RecordFieldList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_LIST }
+impl AstNode for Lifetime {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2342,8 +2342,8 @@ impl AstNode for RecordFieldList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TupleFieldList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD_LIST }
+impl AstNode for LifetimeArg {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2353,8 +2353,8 @@ impl AstNode for TupleFieldList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RecordField {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD }
+impl AstNode for LifetimeParam {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_PARAM }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2364,8 +2364,8 @@ impl AstNode for RecordField {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TupleField {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD }
+impl AstNode for Literal {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2375,8 +2375,8 @@ impl AstNode for TupleField {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for VariantList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT_LIST }
+impl AstNode for LiteralPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2386,8 +2386,8 @@ impl AstNode for VariantList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Variant {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT }
+impl AstNode for LoopExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LOOP_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2397,8 +2397,8 @@ impl AstNode for Variant {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for AssocItemList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST }
+impl AstNode for MacroCall {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_CALL }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2408,8 +2408,8 @@ impl AstNode for AssocItemList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ExternItemList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_ITEM_LIST }
+impl AstNode for MacroDef {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2419,8 +2419,8 @@ impl AstNode for ExternItemList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ConstParam {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_PARAM }
+impl AstNode for MacroEagerInput {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EAGER_INPUT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2430,8 +2430,8 @@ impl AstNode for ConstParam {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for LifetimeParam {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_PARAM }
+impl AstNode for MacroExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2441,8 +2441,8 @@ impl AstNode for LifetimeParam {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TypeParam {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_PARAM }
+impl AstNode for MacroItems {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_ITEMS }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2452,8 +2452,8 @@ impl AstNode for TypeParam {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for WherePred {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_PRED }
+impl AstNode for MacroPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2463,8 +2463,8 @@ impl AstNode for WherePred {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Meta {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == META }
+impl AstNode for MacroRules {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_RULES }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2474,8 +2474,8 @@ impl AstNode for Meta {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ExprStmt {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT }
+impl AstNode for MacroStmts {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2485,8 +2485,8 @@ impl AstNode for ExprStmt {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for LetStmt {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LET_STMT }
+impl AstNode for MacroType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2496,8 +2496,8 @@ impl AstNode for LetStmt {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for LetElse {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LET_ELSE }
+impl AstNode for MatchArm {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2507,8 +2507,8 @@ impl AstNode for LetElse {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ArrayExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_EXPR }
+impl AstNode for MatchArmList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2518,8 +2518,8 @@ impl AstNode for ArrayExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for AsmExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR }
+impl AstNode for MatchExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2529,8 +2529,8 @@ impl AstNode for AsmExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for AwaitExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
+impl AstNode for MatchGuard {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_GUARD }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2540,8 +2540,8 @@ impl AstNode for AwaitExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for BinExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
+impl AstNode for Meta {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == META }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2551,8 +2551,8 @@ impl AstNode for BinExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for BreakExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == BREAK_EXPR }
+impl AstNode for MethodCallExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == METHOD_CALL_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2562,8 +2562,8 @@ impl AstNode for BreakExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for CallExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == CALL_EXPR }
+impl AstNode for Module {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2573,8 +2573,8 @@ impl AstNode for CallExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for CastExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == CAST_EXPR }
+impl AstNode for Name {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == NAME }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2584,8 +2584,8 @@ impl AstNode for CastExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ClosureExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == CLOSURE_EXPR }
+impl AstNode for NameRef {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == NAME_REF }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2595,8 +2595,8 @@ impl AstNode for ClosureExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ContinueExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == CONTINUE_EXPR }
+impl AstNode for NeverType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == NEVER_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2606,8 +2606,8 @@ impl AstNode for ContinueExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for FieldExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_EXPR }
+impl AstNode for OffsetOfExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == OFFSET_OF_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2617,8 +2617,8 @@ impl AstNode for FieldExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ForExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR }
+impl AstNode for OrPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == OR_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2628,8 +2628,8 @@ impl AstNode for ForExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for FormatArgsExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_EXPR }
+impl AstNode for Param {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2639,8 +2639,8 @@ impl AstNode for FormatArgsExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for IfExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR }
+impl AstNode for ParamList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2650,8 +2650,8 @@ impl AstNode for IfExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for IndexExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == INDEX_EXPR }
+impl AstNode for ParenExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2661,8 +2661,8 @@ impl AstNode for IndexExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Literal {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL }
+impl AstNode for ParenPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2672,8 +2672,8 @@ impl AstNode for Literal {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for LoopExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LOOP_EXPR }
+impl AstNode for ParenType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2683,8 +2683,8 @@ impl AstNode for LoopExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MacroExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EXPR }
+impl AstNode for Path {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2694,8 +2694,8 @@ impl AstNode for MacroExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MatchExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_EXPR }
+impl AstNode for PathExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2705,8 +2705,8 @@ impl AstNode for MatchExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MethodCallExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == METHOD_CALL_EXPR }
+impl AstNode for PathPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2716,8 +2716,8 @@ impl AstNode for MethodCallExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for OffsetOfExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == OFFSET_OF_EXPR }
+impl AstNode for PathSegment {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_SEGMENT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2727,8 +2727,8 @@ impl AstNode for OffsetOfExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ParenExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR }
+impl AstNode for PathType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2738,8 +2738,8 @@ impl AstNode for ParenExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for PathExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_EXPR }
+impl AstNode for PrefixExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PREFIX_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2749,8 +2749,8 @@ impl AstNode for PathExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for PrefixExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PREFIX_EXPR }
+impl AstNode for PtrType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == PTR_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2771,8 +2771,8 @@ impl AstNode for RangeExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RecordExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR }
+impl AstNode for RangePat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2782,8 +2782,8 @@ impl AstNode for RecordExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RefExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == REF_EXPR }
+impl AstNode for RecordExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2793,8 +2793,8 @@ impl AstNode for RefExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ReturnExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_EXPR }
+impl AstNode for RecordExprField {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2804,8 +2804,8 @@ impl AstNode for ReturnExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for BecomeExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == BECOME_EXPR }
+impl AstNode for RecordExprFieldList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2815,8 +2815,8 @@ impl AstNode for BecomeExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TryExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR }
+impl AstNode for RecordField {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2826,8 +2826,8 @@ impl AstNode for TryExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TupleExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_EXPR }
+impl AstNode for RecordFieldList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2837,8 +2837,8 @@ impl AstNode for TupleExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for WhileExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == WHILE_EXPR }
+impl AstNode for RecordPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2848,8 +2848,8 @@ impl AstNode for WhileExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for YieldExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == YIELD_EXPR }
+impl AstNode for RecordPatField {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2859,8 +2859,8 @@ impl AstNode for YieldExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for YeetExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == YEET_EXPR }
+impl AstNode for RecordPatFieldList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2870,8 +2870,8 @@ impl AstNode for YeetExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for LetExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LET_EXPR }
+impl AstNode for RefExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == REF_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2881,8 +2881,8 @@ impl AstNode for LetExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for UnderscoreExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == UNDERSCORE_EXPR }
+impl AstNode for RefPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == REF_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2892,8 +2892,8 @@ impl AstNode for UnderscoreExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for FormatArgsArg {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_ARG }
+impl AstNode for RefType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == REF_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2903,8 +2903,8 @@ impl AstNode for FormatArgsArg {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for StmtList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
+impl AstNode for Rename {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RENAME }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2914,8 +2914,8 @@ impl AstNode for StmtList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Label {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL }
+impl AstNode for RestPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == REST_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2925,8 +2925,8 @@ impl AstNode for Label {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RecordExprFieldList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD_LIST }
+impl AstNode for RetType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RET_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2936,8 +2936,8 @@ impl AstNode for RecordExprFieldList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RecordExprField {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD }
+impl AstNode for ReturnExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2947,8 +2947,8 @@ impl AstNode for RecordExprField {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ArgList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == ARG_LIST }
+impl AstNode for SelfParam {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == SELF_PARAM }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2958,8 +2958,8 @@ impl AstNode for ArgList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MatchArmList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
+impl AstNode for SlicePat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2969,8 +2969,8 @@ impl AstNode for MatchArmList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MatchArm {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM }
+impl AstNode for SliceType {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_TYPE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2980,8 +2980,8 @@ impl AstNode for MatchArm {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MatchGuard {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_GUARD }
+impl AstNode for SourceFile {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == SOURCE_FILE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2991,8 +2991,8 @@ impl AstNode for MatchGuard {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ArrayType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_TYPE }
+impl AstNode for Static {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == STATIC }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3002,8 +3002,8 @@ impl AstNode for ArrayType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for DynTraitType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == DYN_TRAIT_TYPE }
+impl AstNode for StmtList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3013,8 +3013,8 @@ impl AstNode for DynTraitType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for FnPtrType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == FN_PTR_TYPE }
+impl AstNode for Struct {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == STRUCT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3024,8 +3024,8 @@ impl AstNode for FnPtrType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ForType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_TYPE }
+impl AstNode for TokenTree {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TOKEN_TREE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3035,8 +3035,8 @@ impl AstNode for ForType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ImplTraitType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_TRAIT_TYPE }
+impl AstNode for Trait {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3046,8 +3046,8 @@ impl AstNode for ImplTraitType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for InferType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == INFER_TYPE }
+impl AstNode for TraitAlias {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT_ALIAS }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3057,8 +3057,8 @@ impl AstNode for InferType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MacroType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_TYPE }
+impl AstNode for TryExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3068,8 +3068,8 @@ impl AstNode for MacroType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for NeverType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == NEVER_TYPE }
+impl AstNode for TupleExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3079,8 +3079,8 @@ impl AstNode for NeverType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ParenType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_TYPE }
+impl AstNode for TupleField {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3090,8 +3090,8 @@ impl AstNode for ParenType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for PtrType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PTR_TYPE }
+impl AstNode for TupleFieldList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3101,8 +3101,8 @@ impl AstNode for PtrType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RefType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == REF_TYPE }
+impl AstNode for TuplePat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3112,8 +3112,8 @@ impl AstNode for RefType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for SliceType {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_TYPE }
+impl AstNode for TupleStructPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_STRUCT_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3134,8 +3134,8 @@ impl AstNode for TupleType {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TypeBound {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND }
+impl AstNode for TypeAlias {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ALIAS }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3145,8 +3145,8 @@ impl AstNode for TypeBound {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for IdentPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT_PAT }
+impl AstNode for TypeArg {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3156,8 +3156,8 @@ impl AstNode for IdentPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for BoxPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_PAT }
+impl AstNode for TypeBound {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3167,8 +3167,8 @@ impl AstNode for BoxPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RestPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == REST_PAT }
+impl AstNode for TypeBoundList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3178,8 +3178,8 @@ impl AstNode for RestPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for LiteralPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL_PAT }
+impl AstNode for TypeParam {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_PARAM }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3189,8 +3189,8 @@ impl AstNode for LiteralPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MacroPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_PAT }
+impl AstNode for UnderscoreExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == UNDERSCORE_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3200,8 +3200,8 @@ impl AstNode for MacroPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for OrPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == OR_PAT }
+impl AstNode for Union {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == UNION }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3211,8 +3211,8 @@ impl AstNode for OrPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ParenPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_PAT }
+impl AstNode for Use {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == USE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3222,8 +3222,8 @@ impl AstNode for ParenPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for PathPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_PAT }
+impl AstNode for UseTree {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3233,8 +3233,8 @@ impl AstNode for PathPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for WildcardPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == WILDCARD_PAT }
+impl AstNode for UseTreeList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3244,8 +3244,8 @@ impl AstNode for WildcardPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RangePat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_PAT }
+impl AstNode for Variant {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3255,8 +3255,8 @@ impl AstNode for RangePat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RecordPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT }
+impl AstNode for VariantList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3266,8 +3266,8 @@ impl AstNode for RecordPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RefPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == REF_PAT }
+impl AstNode for Visibility {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3277,8 +3277,8 @@ impl AstNode for RefPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for SlicePat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_PAT }
+impl AstNode for WhereClause {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3288,8 +3288,8 @@ impl AstNode for SlicePat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TuplePat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_PAT }
+impl AstNode for WherePred {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_PRED }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3299,8 +3299,8 @@ impl AstNode for TuplePat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for TupleStructPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_STRUCT_PAT }
+impl AstNode for WhileExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == WHILE_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3310,8 +3310,8 @@ impl AstNode for TupleStructPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for ConstBlockPat {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_BLOCK_PAT }
+impl AstNode for WildcardPat {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == WILDCARD_PAT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3321,8 +3321,8 @@ impl AstNode for ConstBlockPat {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RecordPatFieldList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD_LIST }
+impl AstNode for YeetExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == YEET_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3332,8 +3332,8 @@ impl AstNode for RecordPatFieldList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for RecordPatField {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD }
+impl AstNode for YieldExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == YIELD_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -3343,139 +3343,64 @@ impl AstNode for RecordPatField {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl From<ArrayType> for Type {
-    fn from(node: ArrayType) -> Type { Type::ArrayType(node) }
-}
-impl From<DynTraitType> for Type {
-    fn from(node: DynTraitType) -> Type { Type::DynTraitType(node) }
-}
-impl From<FnPtrType> for Type {
-    fn from(node: FnPtrType) -> Type { Type::FnPtrType(node) }
-}
-impl From<ForType> for Type {
-    fn from(node: ForType) -> Type { Type::ForType(node) }
-}
-impl From<ImplTraitType> for Type {
-    fn from(node: ImplTraitType) -> Type { Type::ImplTraitType(node) }
-}
-impl From<InferType> for Type {
-    fn from(node: InferType) -> Type { Type::InferType(node) }
-}
-impl From<MacroType> for Type {
-    fn from(node: MacroType) -> Type { Type::MacroType(node) }
-}
-impl From<NeverType> for Type {
-    fn from(node: NeverType) -> Type { Type::NeverType(node) }
-}
-impl From<ParenType> for Type {
-    fn from(node: ParenType) -> Type { Type::ParenType(node) }
-}
-impl From<PathType> for Type {
-    fn from(node: PathType) -> Type { Type::PathType(node) }
-}
-impl From<PtrType> for Type {
-    fn from(node: PtrType) -> Type { Type::PtrType(node) }
-}
-impl From<RefType> for Type {
-    fn from(node: RefType) -> Type { Type::RefType(node) }
+impl From<Enum> for Adt {
+    fn from(node: Enum) -> Adt { Adt::Enum(node) }
 }
-impl From<SliceType> for Type {
-    fn from(node: SliceType) -> Type { Type::SliceType(node) }
+impl From<Struct> for Adt {
+    fn from(node: Struct) -> Adt { Adt::Struct(node) }
 }
-impl From<TupleType> for Type {
-    fn from(node: TupleType) -> Type { Type::TupleType(node) }
+impl From<Union> for Adt {
+    fn from(node: Union) -> Adt { Adt::Union(node) }
 }
-impl AstNode for Type {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        matches!(
-            kind,
-            ARRAY_TYPE
-                | DYN_TRAIT_TYPE
-                | FN_PTR_TYPE
-                | FOR_TYPE
-                | IMPL_TRAIT_TYPE
-                | INFER_TYPE
-                | MACRO_TYPE
-                | NEVER_TYPE
-                | PAREN_TYPE
-                | PATH_TYPE
-                | PTR_TYPE
-                | REF_TYPE
-                | SLICE_TYPE
-                | TUPLE_TYPE
-        )
-    }
+impl AstNode for Adt {
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ENUM | STRUCT | UNION) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
-            ARRAY_TYPE => Type::ArrayType(ArrayType { syntax }),
-            DYN_TRAIT_TYPE => Type::DynTraitType(DynTraitType { syntax }),
-            FN_PTR_TYPE => Type::FnPtrType(FnPtrType { syntax }),
-            FOR_TYPE => Type::ForType(ForType { syntax }),
-            IMPL_TRAIT_TYPE => Type::ImplTraitType(ImplTraitType { syntax }),
-            INFER_TYPE => Type::InferType(InferType { syntax }),
-            MACRO_TYPE => Type::MacroType(MacroType { syntax }),
-            NEVER_TYPE => Type::NeverType(NeverType { syntax }),
-            PAREN_TYPE => Type::ParenType(ParenType { syntax }),
-            PATH_TYPE => Type::PathType(PathType { syntax }),
-            PTR_TYPE => Type::PtrType(PtrType { syntax }),
-            REF_TYPE => Type::RefType(RefType { syntax }),
-            SLICE_TYPE => Type::SliceType(SliceType { syntax }),
-            TUPLE_TYPE => Type::TupleType(TupleType { syntax }),
+            ENUM => Adt::Enum(Enum { syntax }),
+            STRUCT => Adt::Struct(Struct { syntax }),
+            UNION => Adt::Union(Union { syntax }),
             _ => return None,
         };
         Some(res)
     }
     fn syntax(&self) -> &SyntaxNode {
         match self {
-            Type::ArrayType(it) => &it.syntax,
-            Type::DynTraitType(it) => &it.syntax,
-            Type::FnPtrType(it) => &it.syntax,
-            Type::ForType(it) => &it.syntax,
-            Type::ImplTraitType(it) => &it.syntax,
-            Type::InferType(it) => &it.syntax,
-            Type::MacroType(it) => &it.syntax,
-            Type::NeverType(it) => &it.syntax,
-            Type::ParenType(it) => &it.syntax,
-            Type::PathType(it) => &it.syntax,
-            Type::PtrType(it) => &it.syntax,
-            Type::RefType(it) => &it.syntax,
-            Type::SliceType(it) => &it.syntax,
-            Type::TupleType(it) => &it.syntax,
+            Adt::Enum(it) => &it.syntax,
+            Adt::Struct(it) => &it.syntax,
+            Adt::Union(it) => &it.syntax,
         }
     }
 }
-impl From<TypeArg> for GenericArg {
-    fn from(node: TypeArg) -> GenericArg { GenericArg::TypeArg(node) }
+impl From<Const> for AssocItem {
+    fn from(node: Const) -> AssocItem { AssocItem::Const(node) }
 }
-impl From<AssocTypeArg> for GenericArg {
-    fn from(node: AssocTypeArg) -> GenericArg { GenericArg::AssocTypeArg(node) }
+impl From<Fn> for AssocItem {
+    fn from(node: Fn) -> AssocItem { AssocItem::Fn(node) }
 }
-impl From<LifetimeArg> for GenericArg {
-    fn from(node: LifetimeArg) -> GenericArg { GenericArg::LifetimeArg(node) }
+impl From<MacroCall> for AssocItem {
+    fn from(node: MacroCall) -> AssocItem { AssocItem::MacroCall(node) }
 }
-impl From<ConstArg> for GenericArg {
-    fn from(node: ConstArg) -> GenericArg { GenericArg::ConstArg(node) }
+impl From<TypeAlias> for AssocItem {
+    fn from(node: TypeAlias) -> AssocItem { AssocItem::TypeAlias(node) }
 }
-impl AstNode for GenericArg {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG)
-    }
+impl AstNode for AssocItem {
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CONST | FN | MACRO_CALL | TYPE_ALIAS) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
-            TYPE_ARG => GenericArg::TypeArg(TypeArg { syntax }),
-            ASSOC_TYPE_ARG => GenericArg::AssocTypeArg(AssocTypeArg { syntax }),
-            LIFETIME_ARG => GenericArg::LifetimeArg(LifetimeArg { syntax }),
-            CONST_ARG => GenericArg::ConstArg(ConstArg { syntax }),
+            CONST => AssocItem::Const(Const { syntax }),
+            FN => AssocItem::Fn(Fn { syntax }),
+            MACRO_CALL => AssocItem::MacroCall(MacroCall { syntax }),
+            TYPE_ALIAS => AssocItem::TypeAlias(TypeAlias { syntax }),
             _ => return None,
         };
         Some(res)
     }
     fn syntax(&self) -> &SyntaxNode {
         match self {
-            GenericArg::TypeArg(it) => &it.syntax,
-            GenericArg::AssocTypeArg(it) => &it.syntax,
-            GenericArg::LifetimeArg(it) => &it.syntax,
-            GenericArg::ConstArg(it) => &it.syntax,
+            AssocItem::Const(it) => &it.syntax,
+            AssocItem::Fn(it) => &it.syntax,
+            AssocItem::MacroCall(it) => &it.syntax,
+            AssocItem::TypeAlias(it) => &it.syntax,
         }
     }
 }
@@ -3488,6 +3413,9 @@ impl From<AsmExpr> for Expr {
 impl From<AwaitExpr> for Expr {
     fn from(node: AwaitExpr) -> Expr { Expr::AwaitExpr(node) }
 }
+impl From<BecomeExpr> for Expr {
+    fn from(node: BecomeExpr) -> Expr { Expr::BecomeExpr(node) }
+}
 impl From<BinExpr> for Expr {
     fn from(node: BinExpr) -> Expr { Expr::BinExpr(node) }
 }
@@ -3524,6 +3452,9 @@ impl From<IfExpr> for Expr {
 impl From<IndexExpr> for Expr {
     fn from(node: IndexExpr) -> Expr { Expr::IndexExpr(node) }
 }
+impl From<LetExpr> for Expr {
+    fn from(node: LetExpr) -> Expr { Expr::LetExpr(node) }
+}
 impl From<Literal> for Expr {
     fn from(node: Literal) -> Expr { Expr::Literal(node) }
 }
@@ -3563,29 +3494,23 @@ impl From<RefExpr> for Expr {
 impl From<ReturnExpr> for Expr {
     fn from(node: ReturnExpr) -> Expr { Expr::ReturnExpr(node) }
 }
-impl From<BecomeExpr> for Expr {
-    fn from(node: BecomeExpr) -> Expr { Expr::BecomeExpr(node) }
-}
 impl From<TryExpr> for Expr {
     fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) }
 }
 impl From<TupleExpr> for Expr {
     fn from(node: TupleExpr) -> Expr { Expr::TupleExpr(node) }
 }
+impl From<UnderscoreExpr> for Expr {
+    fn from(node: UnderscoreExpr) -> Expr { Expr::UnderscoreExpr(node) }
+}
 impl From<WhileExpr> for Expr {
     fn from(node: WhileExpr) -> Expr { Expr::WhileExpr(node) }
 }
-impl From<YieldExpr> for Expr {
-    fn from(node: YieldExpr) -> Expr { Expr::YieldExpr(node) }
-}
 impl From<YeetExpr> for Expr {
     fn from(node: YeetExpr) -> Expr { Expr::YeetExpr(node) }
 }
-impl From<LetExpr> for Expr {
-    fn from(node: LetExpr) -> Expr { Expr::LetExpr(node) }
-}
-impl From<UnderscoreExpr> for Expr {
-    fn from(node: UnderscoreExpr) -> Expr { Expr::UnderscoreExpr(node) }
+impl From<YieldExpr> for Expr {
+    fn from(node: YieldExpr) -> Expr { Expr::YieldExpr(node) }
 }
 impl AstNode for Expr {
     fn can_cast(kind: SyntaxKind) -> bool {
@@ -3594,6 +3519,7 @@ impl AstNode for Expr {
             ARRAY_EXPR
                 | ASM_EXPR
                 | AWAIT_EXPR
+                | BECOME_EXPR
                 | BIN_EXPR
                 | BLOCK_EXPR
                 | BREAK_EXPR
@@ -3606,6 +3532,7 @@ impl AstNode for Expr {
                 | FORMAT_ARGS_EXPR
                 | IF_EXPR
                 | INDEX_EXPR
+                | LET_EXPR
                 | LITERAL
                 | LOOP_EXPR
                 | MACRO_EXPR
@@ -3619,14 +3546,12 @@ impl AstNode for Expr {
                 | RECORD_EXPR
                 | REF_EXPR
                 | RETURN_EXPR
-                | BECOME_EXPR
                 | TRY_EXPR
                 | TUPLE_EXPR
+                | UNDERSCORE_EXPR
                 | WHILE_EXPR
-                | YIELD_EXPR
                 | YEET_EXPR
-                | LET_EXPR
-                | UNDERSCORE_EXPR
+                | YIELD_EXPR
         )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3634,6 +3559,7 @@ impl AstNode for Expr {
             ARRAY_EXPR => Expr::ArrayExpr(ArrayExpr { syntax }),
             ASM_EXPR => Expr::AsmExpr(AsmExpr { syntax }),
             AWAIT_EXPR => Expr::AwaitExpr(AwaitExpr { syntax }),
+            BECOME_EXPR => Expr::BecomeExpr(BecomeExpr { syntax }),
             BIN_EXPR => Expr::BinExpr(BinExpr { syntax }),
             BLOCK_EXPR => Expr::BlockExpr(BlockExpr { syntax }),
             BREAK_EXPR => Expr::BreakExpr(BreakExpr { syntax }),
@@ -3646,6 +3572,7 @@ impl AstNode for Expr {
             FORMAT_ARGS_EXPR => Expr::FormatArgsExpr(FormatArgsExpr { syntax }),
             IF_EXPR => Expr::IfExpr(IfExpr { syntax }),
             INDEX_EXPR => Expr::IndexExpr(IndexExpr { syntax }),
+            LET_EXPR => Expr::LetExpr(LetExpr { syntax }),
             LITERAL => Expr::Literal(Literal { syntax }),
             LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
             MACRO_EXPR => Expr::MacroExpr(MacroExpr { syntax }),
@@ -3659,14 +3586,12 @@ impl AstNode for Expr {
             RECORD_EXPR => Expr::RecordExpr(RecordExpr { syntax }),
             REF_EXPR => Expr::RefExpr(RefExpr { syntax }),
             RETURN_EXPR => Expr::ReturnExpr(ReturnExpr { syntax }),
-            BECOME_EXPR => Expr::BecomeExpr(BecomeExpr { syntax }),
             TRY_EXPR => Expr::TryExpr(TryExpr { syntax }),
             TUPLE_EXPR => Expr::TupleExpr(TupleExpr { syntax }),
+            UNDERSCORE_EXPR => Expr::UnderscoreExpr(UnderscoreExpr { syntax }),
             WHILE_EXPR => Expr::WhileExpr(WhileExpr { syntax }),
-            YIELD_EXPR => Expr::YieldExpr(YieldExpr { syntax }),
             YEET_EXPR => Expr::YeetExpr(YeetExpr { syntax }),
-            LET_EXPR => Expr::LetExpr(LetExpr { syntax }),
-            UNDERSCORE_EXPR => Expr::UnderscoreExpr(UnderscoreExpr { syntax }),
+            YIELD_EXPR => Expr::YieldExpr(YieldExpr { syntax }),
             _ => return None,
         };
         Some(res)
@@ -3676,6 +3601,7 @@ impl AstNode for Expr {
             Expr::ArrayExpr(it) => &it.syntax,
             Expr::AsmExpr(it) => &it.syntax,
             Expr::AwaitExpr(it) => &it.syntax,
+            Expr::BecomeExpr(it) => &it.syntax,
             Expr::BinExpr(it) => &it.syntax,
             Expr::BlockExpr(it) => &it.syntax,
             Expr::BreakExpr(it) => &it.syntax,
@@ -3688,6 +3614,7 @@ impl AstNode for Expr {
             Expr::FormatArgsExpr(it) => &it.syntax,
             Expr::IfExpr(it) => &it.syntax,
             Expr::IndexExpr(it) => &it.syntax,
+            Expr::LetExpr(it) => &it.syntax,
             Expr::Literal(it) => &it.syntax,
             Expr::LoopExpr(it) => &it.syntax,
             Expr::MacroExpr(it) => &it.syntax,
@@ -3701,14 +3628,133 @@ impl AstNode for Expr {
             Expr::RecordExpr(it) => &it.syntax,
             Expr::RefExpr(it) => &it.syntax,
             Expr::ReturnExpr(it) => &it.syntax,
-            Expr::BecomeExpr(it) => &it.syntax,
             Expr::TryExpr(it) => &it.syntax,
             Expr::TupleExpr(it) => &it.syntax,
+            Expr::UnderscoreExpr(it) => &it.syntax,
             Expr::WhileExpr(it) => &it.syntax,
-            Expr::YieldExpr(it) => &it.syntax,
             Expr::YeetExpr(it) => &it.syntax,
-            Expr::LetExpr(it) => &it.syntax,
-            Expr::UnderscoreExpr(it) => &it.syntax,
+            Expr::YieldExpr(it) => &it.syntax,
+        }
+    }
+}
+impl From<Fn> for ExternItem {
+    fn from(node: Fn) -> ExternItem { ExternItem::Fn(node) }
+}
+impl From<MacroCall> for ExternItem {
+    fn from(node: MacroCall) -> ExternItem { ExternItem::MacroCall(node) }
+}
+impl From<Static> for ExternItem {
+    fn from(node: Static) -> ExternItem { ExternItem::Static(node) }
+}
+impl From<TypeAlias> for ExternItem {
+    fn from(node: TypeAlias) -> ExternItem { ExternItem::TypeAlias(node) }
+}
+impl AstNode for ExternItem {
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FN | MACRO_CALL | STATIC | TYPE_ALIAS) }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        let res = match syntax.kind() {
+            FN => ExternItem::Fn(Fn { syntax }),
+            MACRO_CALL => ExternItem::MacroCall(MacroCall { syntax }),
+            STATIC => ExternItem::Static(Static { syntax }),
+            TYPE_ALIAS => ExternItem::TypeAlias(TypeAlias { syntax }),
+            _ => return None,
+        };
+        Some(res)
+    }
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            ExternItem::Fn(it) => &it.syntax,
+            ExternItem::MacroCall(it) => &it.syntax,
+            ExternItem::Static(it) => &it.syntax,
+            ExternItem::TypeAlias(it) => &it.syntax,
+        }
+    }
+}
+impl From<RecordFieldList> for FieldList {
+    fn from(node: RecordFieldList) -> FieldList { FieldList::RecordFieldList(node) }
+}
+impl From<TupleFieldList> for FieldList {
+    fn from(node: TupleFieldList) -> FieldList { FieldList::TupleFieldList(node) }
+}
+impl AstNode for FieldList {
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, RECORD_FIELD_LIST | TUPLE_FIELD_LIST) }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        let res = match syntax.kind() {
+            RECORD_FIELD_LIST => FieldList::RecordFieldList(RecordFieldList { syntax }),
+            TUPLE_FIELD_LIST => FieldList::TupleFieldList(TupleFieldList { syntax }),
+            _ => return None,
+        };
+        Some(res)
+    }
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            FieldList::RecordFieldList(it) => &it.syntax,
+            FieldList::TupleFieldList(it) => &it.syntax,
+        }
+    }
+}
+impl From<AssocTypeArg> for GenericArg {
+    fn from(node: AssocTypeArg) -> GenericArg { GenericArg::AssocTypeArg(node) }
+}
+impl From<ConstArg> for GenericArg {
+    fn from(node: ConstArg) -> GenericArg { GenericArg::ConstArg(node) }
+}
+impl From<LifetimeArg> for GenericArg {
+    fn from(node: LifetimeArg) -> GenericArg { GenericArg::LifetimeArg(node) }
+}
+impl From<TypeArg> for GenericArg {
+    fn from(node: TypeArg) -> GenericArg { GenericArg::TypeArg(node) }
+}
+impl AstNode for GenericArg {
+    fn can_cast(kind: SyntaxKind) -> bool {
+        matches!(kind, ASSOC_TYPE_ARG | CONST_ARG | LIFETIME_ARG | TYPE_ARG)
+    }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        let res = match syntax.kind() {
+            ASSOC_TYPE_ARG => GenericArg::AssocTypeArg(AssocTypeArg { syntax }),
+            CONST_ARG => GenericArg::ConstArg(ConstArg { syntax }),
+            LIFETIME_ARG => GenericArg::LifetimeArg(LifetimeArg { syntax }),
+            TYPE_ARG => GenericArg::TypeArg(TypeArg { syntax }),
+            _ => return None,
+        };
+        Some(res)
+    }
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            GenericArg::AssocTypeArg(it) => &it.syntax,
+            GenericArg::ConstArg(it) => &it.syntax,
+            GenericArg::LifetimeArg(it) => &it.syntax,
+            GenericArg::TypeArg(it) => &it.syntax,
+        }
+    }
+}
+impl From<ConstParam> for GenericParam {
+    fn from(node: ConstParam) -> GenericParam { GenericParam::ConstParam(node) }
+}
+impl From<LifetimeParam> for GenericParam {
+    fn from(node: LifetimeParam) -> GenericParam { GenericParam::LifetimeParam(node) }
+}
+impl From<TypeParam> for GenericParam {
+    fn from(node: TypeParam) -> GenericParam { GenericParam::TypeParam(node) }
+}
+impl AstNode for GenericParam {
+    fn can_cast(kind: SyntaxKind) -> bool {
+        matches!(kind, CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM)
+    }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        let res = match syntax.kind() {
+            CONST_PARAM => GenericParam::ConstParam(ConstParam { syntax }),
+            LIFETIME_PARAM => GenericParam::LifetimeParam(LifetimeParam { syntax }),
+            TYPE_PARAM => GenericParam::TypeParam(TypeParam { syntax }),
+            _ => return None,
+        };
+        Some(res)
+    }
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            GenericParam::ConstParam(it) => &it.syntax,
+            GenericParam::LifetimeParam(it) => &it.syntax,
+            GenericParam::TypeParam(it) => &it.syntax,
         }
     }
 }
@@ -3733,12 +3779,12 @@ impl From<Impl> for Item {
 impl From<MacroCall> for Item {
     fn from(node: MacroCall) -> Item { Item::MacroCall(node) }
 }
-impl From<MacroRules> for Item {
-    fn from(node: MacroRules) -> Item { Item::MacroRules(node) }
-}
 impl From<MacroDef> for Item {
     fn from(node: MacroDef) -> Item { Item::MacroDef(node) }
 }
+impl From<MacroRules> for Item {
+    fn from(node: MacroRules) -> Item { Item::MacroRules(node) }
+}
 impl From<Module> for Item {
     fn from(node: Module) -> Item { Item::Module(node) }
 }
@@ -3774,8 +3820,8 @@ impl AstNode for Item {
                 | FN
                 | IMPL
                 | MACRO_CALL
-                | MACRO_RULES
                 | MACRO_DEF
+                | MACRO_RULES
                 | MODULE
                 | STATIC
                 | STRUCT
@@ -3795,8 +3841,8 @@ impl AstNode for Item {
             FN => Item::Fn(Fn { syntax }),
             IMPL => Item::Impl(Impl { syntax }),
             MACRO_CALL => Item::MacroCall(MacroCall { syntax }),
-            MACRO_RULES => Item::MacroRules(MacroRules { syntax }),
             MACRO_DEF => Item::MacroDef(MacroDef { syntax }),
+            MACRO_RULES => Item::MacroRules(MacroRules { syntax }),
             MODULE => Item::Module(Module { syntax }),
             STATIC => Item::Static(Static { syntax }),
             STRUCT => Item::Struct(Struct { syntax }),
@@ -3818,8 +3864,8 @@ impl AstNode for Item {
             Item::Fn(it) => &it.syntax,
             Item::Impl(it) => &it.syntax,
             Item::MacroCall(it) => &it.syntax,
-            Item::MacroRules(it) => &it.syntax,
             Item::MacroDef(it) => &it.syntax,
+            Item::MacroRules(it) => &it.syntax,
             Item::Module(it) => &it.syntax,
             Item::Static(it) => &it.syntax,
             Item::Struct(it) => &it.syntax,
@@ -3831,24 +3877,15 @@ impl AstNode for Item {
         }
     }
 }
-impl From<ExprStmt> for Stmt {
-    fn from(node: ExprStmt) -> Stmt { Stmt::ExprStmt(node) }
-}
-impl From<Item> for Stmt {
-    fn from(node: Item) -> Stmt { Stmt::Item(node) }
+impl From<BoxPat> for Pat {
+    fn from(node: BoxPat) -> Pat { Pat::BoxPat(node) }
 }
-impl From<LetStmt> for Stmt {
-    fn from(node: LetStmt) -> Stmt { Stmt::LetStmt(node) }
+impl From<ConstBlockPat> for Pat {
+    fn from(node: ConstBlockPat) -> Pat { Pat::ConstBlockPat(node) }
 }
 impl From<IdentPat> for Pat {
     fn from(node: IdentPat) -> Pat { Pat::IdentPat(node) }
 }
-impl From<BoxPat> for Pat {
-    fn from(node: BoxPat) -> Pat { Pat::BoxPat(node) }
-}
-impl From<RestPat> for Pat {
-    fn from(node: RestPat) -> Pat { Pat::RestPat(node) }
-}
 impl From<LiteralPat> for Pat {
     fn from(node: LiteralPat) -> Pat { Pat::LiteralPat(node) }
 }
@@ -3864,9 +3901,6 @@ impl From<ParenPat> for Pat {
 impl From<PathPat> for Pat {
     fn from(node: PathPat) -> Pat { Pat::PathPat(node) }
 }
-impl From<WildcardPat> for Pat {
-    fn from(node: WildcardPat) -> Pat { Pat::WildcardPat(node) }
-}
 impl From<RangePat> for Pat {
     fn from(node: RangePat) -> Pat { Pat::RangePat(node) }
 }
@@ -3876,6 +3910,9 @@ impl From<RecordPat> for Pat {
 impl From<RefPat> for Pat {
     fn from(node: RefPat) -> Pat { Pat::RefPat(node) }
 }
+impl From<RestPat> for Pat {
+    fn from(node: RestPat) -> Pat { Pat::RestPat(node) }
+}
 impl From<SlicePat> for Pat {
     fn from(node: SlicePat) -> Pat { Pat::SlicePat(node) }
 }
@@ -3885,218 +3922,181 @@ impl From<TuplePat> for Pat {
 impl From<TupleStructPat> for Pat {
     fn from(node: TupleStructPat) -> Pat { Pat::TupleStructPat(node) }
 }
-impl From<ConstBlockPat> for Pat {
-    fn from(node: ConstBlockPat) -> Pat { Pat::ConstBlockPat(node) }
+impl From<WildcardPat> for Pat {
+    fn from(node: WildcardPat) -> Pat { Pat::WildcardPat(node) }
 }
 impl AstNode for Pat {
     fn can_cast(kind: SyntaxKind) -> bool {
         matches!(
             kind,
-            IDENT_PAT
-                | BOX_PAT
-                | REST_PAT
+            BOX_PAT
+                | CONST_BLOCK_PAT
+                | IDENT_PAT
                 | LITERAL_PAT
                 | MACRO_PAT
                 | OR_PAT
                 | PAREN_PAT
                 | PATH_PAT
-                | WILDCARD_PAT
                 | RANGE_PAT
                 | RECORD_PAT
                 | REF_PAT
+                | REST_PAT
                 | SLICE_PAT
                 | TUPLE_PAT
                 | TUPLE_STRUCT_PAT
-                | CONST_BLOCK_PAT
+                | WILDCARD_PAT
         )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
-            IDENT_PAT => Pat::IdentPat(IdentPat { syntax }),
             BOX_PAT => Pat::BoxPat(BoxPat { syntax }),
-            REST_PAT => Pat::RestPat(RestPat { syntax }),
+            CONST_BLOCK_PAT => Pat::ConstBlockPat(ConstBlockPat { syntax }),
+            IDENT_PAT => Pat::IdentPat(IdentPat { syntax }),
             LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }),
             MACRO_PAT => Pat::MacroPat(MacroPat { syntax }),
             OR_PAT => Pat::OrPat(OrPat { syntax }),
             PAREN_PAT => Pat::ParenPat(ParenPat { syntax }),
             PATH_PAT => Pat::PathPat(PathPat { syntax }),
-            WILDCARD_PAT => Pat::WildcardPat(WildcardPat { syntax }),
             RANGE_PAT => Pat::RangePat(RangePat { syntax }),
             RECORD_PAT => Pat::RecordPat(RecordPat { syntax }),
             REF_PAT => Pat::RefPat(RefPat { syntax }),
+            REST_PAT => Pat::RestPat(RestPat { syntax }),
             SLICE_PAT => Pat::SlicePat(SlicePat { syntax }),
             TUPLE_PAT => Pat::TuplePat(TuplePat { syntax }),
             TUPLE_STRUCT_PAT => Pat::TupleStructPat(TupleStructPat { syntax }),
-            CONST_BLOCK_PAT => Pat::ConstBlockPat(ConstBlockPat { syntax }),
+            WILDCARD_PAT => Pat::WildcardPat(WildcardPat { syntax }),
             _ => return None,
         };
         Some(res)
     }
     fn syntax(&self) -> &SyntaxNode {
         match self {
-            Pat::IdentPat(it) => &it.syntax,
             Pat::BoxPat(it) => &it.syntax,
-            Pat::RestPat(it) => &it.syntax,
+            Pat::ConstBlockPat(it) => &it.syntax,
+            Pat::IdentPat(it) => &it.syntax,
             Pat::LiteralPat(it) => &it.syntax,
             Pat::MacroPat(it) => &it.syntax,
             Pat::OrPat(it) => &it.syntax,
             Pat::ParenPat(it) => &it.syntax,
             Pat::PathPat(it) => &it.syntax,
-            Pat::WildcardPat(it) => &it.syntax,
             Pat::RangePat(it) => &it.syntax,
             Pat::RecordPat(it) => &it.syntax,
             Pat::RefPat(it) => &it.syntax,
+            Pat::RestPat(it) => &it.syntax,
             Pat::SlicePat(it) => &it.syntax,
             Pat::TuplePat(it) => &it.syntax,
             Pat::TupleStructPat(it) => &it.syntax,
-            Pat::ConstBlockPat(it) => &it.syntax,
-        }
-    }
-}
-impl From<RecordFieldList> for FieldList {
-    fn from(node: RecordFieldList) -> FieldList { FieldList::RecordFieldList(node) }
-}
-impl From<TupleFieldList> for FieldList {
-    fn from(node: TupleFieldList) -> FieldList { FieldList::TupleFieldList(node) }
-}
-impl AstNode for FieldList {
-    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, RECORD_FIELD_LIST | TUPLE_FIELD_LIST) }
-    fn cast(syntax: SyntaxNode) -> Option<Self> {
-        let res = match syntax.kind() {
-            RECORD_FIELD_LIST => FieldList::RecordFieldList(RecordFieldList { syntax }),
-            TUPLE_FIELD_LIST => FieldList::TupleFieldList(TupleFieldList { syntax }),
-            _ => return None,
-        };
-        Some(res)
-    }
-    fn syntax(&self) -> &SyntaxNode {
-        match self {
-            FieldList::RecordFieldList(it) => &it.syntax,
-            FieldList::TupleFieldList(it) => &it.syntax,
+            Pat::WildcardPat(it) => &it.syntax,
         }
     }
 }
-impl From<Enum> for Adt {
-    fn from(node: Enum) -> Adt { Adt::Enum(node) }
+impl From<ExprStmt> for Stmt {
+    fn from(node: ExprStmt) -> Stmt { Stmt::ExprStmt(node) }
 }
-impl From<Struct> for Adt {
-    fn from(node: Struct) -> Adt { Adt::Struct(node) }
+impl From<Item> for Stmt {
+    fn from(node: Item) -> Stmt { Stmt::Item(node) }
 }
-impl From<Union> for Adt {
-    fn from(node: Union) -> Adt { Adt::Union(node) }
+impl From<LetStmt> for Stmt {
+    fn from(node: LetStmt) -> Stmt { Stmt::LetStmt(node) }
 }
-impl AstNode for Adt {
-    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ENUM | STRUCT | UNION) }
-    fn cast(syntax: SyntaxNode) -> Option<Self> {
-        let res = match syntax.kind() {
-            ENUM => Adt::Enum(Enum { syntax }),
-            STRUCT => Adt::Struct(Struct { syntax }),
-            UNION => Adt::Union(Union { syntax }),
-            _ => return None,
-        };
-        Some(res)
-    }
-    fn syntax(&self) -> &SyntaxNode {
-        match self {
-            Adt::Enum(it) => &it.syntax,
-            Adt::Struct(it) => &it.syntax,
-            Adt::Union(it) => &it.syntax,
-        }
-    }
+impl From<ArrayType> for Type {
+    fn from(node: ArrayType) -> Type { Type::ArrayType(node) }
 }
-impl From<Const> for AssocItem {
-    fn from(node: Const) -> AssocItem { AssocItem::Const(node) }
+impl From<DynTraitType> for Type {
+    fn from(node: DynTraitType) -> Type { Type::DynTraitType(node) }
 }
-impl From<Fn> for AssocItem {
-    fn from(node: Fn) -> AssocItem { AssocItem::Fn(node) }
+impl From<FnPtrType> for Type {
+    fn from(node: FnPtrType) -> Type { Type::FnPtrType(node) }
 }
-impl From<MacroCall> for AssocItem {
-    fn from(node: MacroCall) -> AssocItem { AssocItem::MacroCall(node) }
+impl From<ForType> for Type {
+    fn from(node: ForType) -> Type { Type::ForType(node) }
 }
-impl From<TypeAlias> for AssocItem {
-    fn from(node: TypeAlias) -> AssocItem { AssocItem::TypeAlias(node) }
+impl From<ImplTraitType> for Type {
+    fn from(node: ImplTraitType) -> Type { Type::ImplTraitType(node) }
 }
-impl AstNode for AssocItem {
-    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CONST | FN | MACRO_CALL | TYPE_ALIAS) }
-    fn cast(syntax: SyntaxNode) -> Option<Self> {
-        let res = match syntax.kind() {
-            CONST => AssocItem::Const(Const { syntax }),
-            FN => AssocItem::Fn(Fn { syntax }),
-            MACRO_CALL => AssocItem::MacroCall(MacroCall { syntax }),
-            TYPE_ALIAS => AssocItem::TypeAlias(TypeAlias { syntax }),
-            _ => return None,
-        };
-        Some(res)
-    }
-    fn syntax(&self) -> &SyntaxNode {
-        match self {
-            AssocItem::Const(it) => &it.syntax,
-            AssocItem::Fn(it) => &it.syntax,
-            AssocItem::MacroCall(it) => &it.syntax,
-            AssocItem::TypeAlias(it) => &it.syntax,
-        }
-    }
+impl From<InferType> for Type {
+    fn from(node: InferType) -> Type { Type::InferType(node) }
 }
-impl From<Fn> for ExternItem {
-    fn from(node: Fn) -> ExternItem { ExternItem::Fn(node) }
+impl From<MacroType> for Type {
+    fn from(node: MacroType) -> Type { Type::MacroType(node) }
 }
-impl From<MacroCall> for ExternItem {
-    fn from(node: MacroCall) -> ExternItem { ExternItem::MacroCall(node) }
+impl From<NeverType> for Type {
+    fn from(node: NeverType) -> Type { Type::NeverType(node) }
 }
-impl From<Static> for ExternItem {
-    fn from(node: Static) -> ExternItem { ExternItem::Static(node) }
+impl From<ParenType> for Type {
+    fn from(node: ParenType) -> Type { Type::ParenType(node) }
 }
-impl From<TypeAlias> for ExternItem {
-    fn from(node: TypeAlias) -> ExternItem { ExternItem::TypeAlias(node) }
+impl From<PathType> for Type {
+    fn from(node: PathType) -> Type { Type::PathType(node) }
 }
-impl AstNode for ExternItem {
-    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FN | MACRO_CALL | STATIC | TYPE_ALIAS) }
-    fn cast(syntax: SyntaxNode) -> Option<Self> {
-        let res = match syntax.kind() {
-            FN => ExternItem::Fn(Fn { syntax }),
-            MACRO_CALL => ExternItem::MacroCall(MacroCall { syntax }),
-            STATIC => ExternItem::Static(Static { syntax }),
-            TYPE_ALIAS => ExternItem::TypeAlias(TypeAlias { syntax }),
-            _ => return None,
-        };
-        Some(res)
-    }
-    fn syntax(&self) -> &SyntaxNode {
-        match self {
-            ExternItem::Fn(it) => &it.syntax,
-            ExternItem::MacroCall(it) => &it.syntax,
-            ExternItem::Static(it) => &it.syntax,
-            ExternItem::TypeAlias(it) => &it.syntax,
-        }
-    }
+impl From<PtrType> for Type {
+    fn from(node: PtrType) -> Type { Type::PtrType(node) }
 }
-impl From<ConstParam> for GenericParam {
-    fn from(node: ConstParam) -> GenericParam { GenericParam::ConstParam(node) }
+impl From<RefType> for Type {
+    fn from(node: RefType) -> Type { Type::RefType(node) }
 }
-impl From<LifetimeParam> for GenericParam {
-    fn from(node: LifetimeParam) -> GenericParam { GenericParam::LifetimeParam(node) }
+impl From<SliceType> for Type {
+    fn from(node: SliceType) -> Type { Type::SliceType(node) }
 }
-impl From<TypeParam> for GenericParam {
-    fn from(node: TypeParam) -> GenericParam { GenericParam::TypeParam(node) }
+impl From<TupleType> for Type {
+    fn from(node: TupleType) -> Type { Type::TupleType(node) }
 }
-impl AstNode for GenericParam {
+impl AstNode for Type {
     fn can_cast(kind: SyntaxKind) -> bool {
-        matches!(kind, CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM)
+        matches!(
+            kind,
+            ARRAY_TYPE
+                | DYN_TRAIT_TYPE
+                | FN_PTR_TYPE
+                | FOR_TYPE
+                | IMPL_TRAIT_TYPE
+                | INFER_TYPE
+                | MACRO_TYPE
+                | NEVER_TYPE
+                | PAREN_TYPE
+                | PATH_TYPE
+                | PTR_TYPE
+                | REF_TYPE
+                | SLICE_TYPE
+                | TUPLE_TYPE
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
-            CONST_PARAM => GenericParam::ConstParam(ConstParam { syntax }),
-            LIFETIME_PARAM => GenericParam::LifetimeParam(LifetimeParam { syntax }),
-            TYPE_PARAM => GenericParam::TypeParam(TypeParam { syntax }),
+            ARRAY_TYPE => Type::ArrayType(ArrayType { syntax }),
+            DYN_TRAIT_TYPE => Type::DynTraitType(DynTraitType { syntax }),
+            FN_PTR_TYPE => Type::FnPtrType(FnPtrType { syntax }),
+            FOR_TYPE => Type::ForType(ForType { syntax }),
+            IMPL_TRAIT_TYPE => Type::ImplTraitType(ImplTraitType { syntax }),
+            INFER_TYPE => Type::InferType(InferType { syntax }),
+            MACRO_TYPE => Type::MacroType(MacroType { syntax }),
+            NEVER_TYPE => Type::NeverType(NeverType { syntax }),
+            PAREN_TYPE => Type::ParenType(ParenType { syntax }),
+            PATH_TYPE => Type::PathType(PathType { syntax }),
+            PTR_TYPE => Type::PtrType(PtrType { syntax }),
+            REF_TYPE => Type::RefType(RefType { syntax }),
+            SLICE_TYPE => Type::SliceType(SliceType { syntax }),
+            TUPLE_TYPE => Type::TupleType(TupleType { syntax }),
             _ => return None,
         };
         Some(res)
     }
     fn syntax(&self) -> &SyntaxNode {
         match self {
-            GenericParam::ConstParam(it) => &it.syntax,
-            GenericParam::LifetimeParam(it) => &it.syntax,
-            GenericParam::TypeParam(it) => &it.syntax,
+            Type::ArrayType(it) => &it.syntax,
+            Type::DynTraitType(it) => &it.syntax,
+            Type::FnPtrType(it) => &it.syntax,
+            Type::ForType(it) => &it.syntax,
+            Type::ImplTraitType(it) => &it.syntax,
+            Type::InferType(it) => &it.syntax,
+            Type::MacroType(it) => &it.syntax,
+            Type::NeverType(it) => &it.syntax,
+            Type::ParenType(it) => &it.syntax,
+            Type::PathType(it) => &it.syntax,
+            Type::PtrType(it) => &it.syntax,
+            Type::RefType(it) => &it.syntax,
+            Type::SliceType(it) => &it.syntax,
+            Type::TupleType(it) => &it.syntax,
         }
     }
 }
@@ -4123,78 +4123,78 @@ impl AstNode for AnyHasAttrs {
     fn can_cast(kind: SyntaxKind) -> bool {
         matches!(
             kind,
-            MACRO_CALL
-                | SOURCE_FILE
-                | CONST
-                | ENUM
-                | EXTERN_BLOCK
-                | EXTERN_CRATE
-                | FN
-                | IMPL
-                | MACRO_RULES
-                | MACRO_DEF
-                | MODULE
-                | STATIC
-                | STRUCT
-                | TRAIT
-                | TRAIT_ALIAS
-                | TYPE_ALIAS
-                | UNION
-                | USE
-                | ITEM_LIST
-                | BLOCK_EXPR
-                | SELF_PARAM
-                | PARAM
-                | RECORD_FIELD
-                | TUPLE_FIELD
-                | VARIANT
-                | ASSOC_ITEM_LIST
-                | EXTERN_ITEM_LIST
-                | CONST_PARAM
-                | LIFETIME_PARAM
-                | TYPE_PARAM
-                | LET_STMT
-                | ARRAY_EXPR
+            ARRAY_EXPR
                 | ASM_EXPR
+                | ASSOC_ITEM_LIST
                 | AWAIT_EXPR
+                | BECOME_EXPR
                 | BIN_EXPR
+                | BLOCK_EXPR
                 | BREAK_EXPR
                 | CALL_EXPR
                 | CAST_EXPR
                 | CLOSURE_EXPR
+                | CONST
+                | CONST_PARAM
                 | CONTINUE_EXPR
+                | ENUM
+                | EXTERN_BLOCK
+                | EXTERN_CRATE
+                | EXTERN_ITEM_LIST
                 | FIELD_EXPR
+                | FN
                 | FOR_EXPR
                 | FORMAT_ARGS_EXPR
+                | IDENT_PAT
                 | IF_EXPR
+                | IMPL
                 | INDEX_EXPR
+                | ITEM_LIST
+                | LET_EXPR
+                | LET_STMT
+                | LIFETIME_PARAM
                 | LITERAL
                 | LOOP_EXPR
+                | MACRO_CALL
+                | MACRO_DEF
+                | MACRO_RULES
+                | MATCH_ARM
+                | MATCH_ARM_LIST
                 | MATCH_EXPR
                 | METHOD_CALL_EXPR
+                | MODULE
                 | OFFSET_OF_EXPR
+                | PARAM
                 | PAREN_EXPR
                 | PATH_EXPR
                 | PREFIX_EXPR
                 | RANGE_EXPR
+                | RECORD_EXPR_FIELD
+                | RECORD_EXPR_FIELD_LIST
+                | RECORD_FIELD
+                | RECORD_PAT_FIELD
                 | REF_EXPR
+                | REST_PAT
                 | RETURN_EXPR
-                | BECOME_EXPR
+                | SELF_PARAM
+                | SOURCE_FILE
+                | STATIC
+                | STMT_LIST
+                | STRUCT
+                | TRAIT
+                | TRAIT_ALIAS
                 | TRY_EXPR
                 | TUPLE_EXPR
+                | TUPLE_FIELD
+                | TYPE_ALIAS
+                | TYPE_PARAM
+                | UNDERSCORE_EXPR
+                | UNION
+                | USE
+                | VARIANT
                 | WHILE_EXPR
-                | YIELD_EXPR
                 | YEET_EXPR
-                | LET_EXPR
-                | UNDERSCORE_EXPR
-                | STMT_LIST
-                | RECORD_EXPR_FIELD_LIST
-                | RECORD_EXPR_FIELD
-                | MATCH_ARM_LIST
-                | MATCH_ARM
-                | IDENT_PAT
-                | REST_PAT
-                | RECORD_PAT_FIELD
+                | YIELD_EXPR
         )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4212,26 +4212,26 @@ impl AstNode for AnyHasDocComments {
     fn can_cast(kind: SyntaxKind) -> bool {
         matches!(
             kind,
-            MACRO_CALL
-                | SOURCE_FILE
-                | CONST
+            CONST
                 | ENUM
                 | EXTERN_BLOCK
                 | EXTERN_CRATE
                 | FN
                 | IMPL
-                | MACRO_RULES
+                | MACRO_CALL
                 | MACRO_DEF
+                | MACRO_RULES
                 | MODULE
+                | RECORD_FIELD
+                | SOURCE_FILE
                 | STATIC
                 | STRUCT
                 | TRAIT
                 | TRAIT_ALIAS
+                | TUPLE_FIELD
                 | TYPE_ALIAS
                 | UNION
                 | USE
-                | RECORD_FIELD
-                | TUPLE_FIELD
                 | VARIANT
         )
     }
@@ -4275,7 +4275,7 @@ impl AnyHasModuleItem {
     }
 }
 impl AstNode for AnyHasModuleItem {
-    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, MACRO_ITEMS | SOURCE_FILE | ITEM_LIST) }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ITEM_LIST | MACRO_ITEMS | SOURCE_FILE) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then_some(AnyHasModuleItem { syntax })
     }
@@ -4292,25 +4292,25 @@ impl AstNode for AnyHasName {
         matches!(
             kind,
             CONST
+                | CONST_PARAM
                 | ENUM
                 | FN
-                | MACRO_RULES
+                | FORMAT_ARGS_ARG
+                | IDENT_PAT
                 | MACRO_DEF
+                | MACRO_RULES
                 | MODULE
+                | RECORD_FIELD
+                | RENAME
+                | SELF_PARAM
                 | STATIC
                 | STRUCT
                 | TRAIT
                 | TRAIT_ALIAS
                 | TYPE_ALIAS
+                | TYPE_PARAM
                 | UNION
-                | RENAME
-                | SELF_PARAM
-                | RECORD_FIELD
                 | VARIANT
-                | CONST_PARAM
-                | TYPE_PARAM
-                | FORMAT_ARGS_ARG
-                | IDENT_PAT
         )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4328,7 +4328,7 @@ impl AstNode for AnyHasTypeBounds {
     fn can_cast(kind: SyntaxKind) -> bool {
         matches!(
             kind,
-            ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED
+            ASSOC_TYPE_ARG | LIFETIME_PARAM | TRAIT | TYPE_ALIAS | TYPE_PARAM | WHERE_PRED
         )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4351,18 +4351,18 @@ impl AstNode for AnyHasVisibility {
                 | EXTERN_CRATE
                 | FN
                 | IMPL
-                | MACRO_RULES
                 | MACRO_DEF
+                | MACRO_RULES
                 | MODULE
+                | RECORD_FIELD
                 | STATIC
                 | STRUCT
                 | TRAIT
                 | TRAIT_ALIAS
+                | TUPLE_FIELD
                 | TYPE_ALIAS
                 | UNION
                 | USE
-                | RECORD_FIELD
-                | TUPLE_FIELD
                 | VARIANT
         )
     }
@@ -4371,12 +4371,12 @@ impl AstNode for AnyHasVisibility {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl std::fmt::Display for Type {
+impl std::fmt::Display for Adt {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for GenericArg {
+impl std::fmt::Display for AssocItem {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
@@ -4386,477 +4386,477 @@ impl std::fmt::Display for Expr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Item {
+impl std::fmt::Display for ExternItem {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Stmt {
+impl std::fmt::Display for FieldList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Pat {
+impl std::fmt::Display for GenericArg {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for FieldList {
+impl std::fmt::Display for GenericParam {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Adt {
+impl std::fmt::Display for Item {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for AssocItem {
+impl std::fmt::Display for Pat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ExternItem {
+impl std::fmt::Display for Stmt {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for GenericParam {
+impl std::fmt::Display for Type {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Name {
+impl std::fmt::Display for Abi {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for NameRef {
+impl std::fmt::Display for ArgList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Lifetime {
+impl std::fmt::Display for ArrayExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Path {
+impl std::fmt::Display for ArrayType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for PathSegment {
+impl std::fmt::Display for AsmExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for GenericArgList {
+impl std::fmt::Display for AssocItemList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ParamList {
+impl std::fmt::Display for AssocTypeArg {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RetType {
+impl std::fmt::Display for Attr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for PathType {
+impl std::fmt::Display for AwaitExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TypeArg {
+impl std::fmt::Display for BecomeExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for AssocTypeArg {
+impl std::fmt::Display for BinExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for LifetimeArg {
+impl std::fmt::Display for BlockExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ConstArg {
+impl std::fmt::Display for BoxPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TypeBoundList {
+impl std::fmt::Display for BreakExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MacroCall {
+impl std::fmt::Display for CallExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Attr {
+impl std::fmt::Display for CastExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TokenTree {
+impl std::fmt::Display for ClosureExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MacroItems {
+impl std::fmt::Display for Const {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MacroEagerInput {
+impl std::fmt::Display for ConstArg {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MacroStmts {
+impl std::fmt::Display for ConstBlockPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for SourceFile {
+impl std::fmt::Display for ConstParam {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Const {
+impl std::fmt::Display for ContinueExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Enum {
+impl std::fmt::Display for DynTraitType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ExternBlock {
+impl std::fmt::Display for Enum {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ExternCrate {
+impl std::fmt::Display for ExprStmt {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Fn {
+impl std::fmt::Display for ExternBlock {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Impl {
+impl std::fmt::Display for ExternCrate {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MacroRules {
+impl std::fmt::Display for ExternItemList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MacroDef {
+impl std::fmt::Display for FieldExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Module {
+impl std::fmt::Display for Fn {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Static {
+impl std::fmt::Display for FnPtrType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Struct {
+impl std::fmt::Display for ForExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Trait {
+impl std::fmt::Display for ForType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TraitAlias {
+impl std::fmt::Display for FormatArgsArg {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TypeAlias {
+impl std::fmt::Display for FormatArgsExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Union {
+impl std::fmt::Display for GenericArgList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Use {
+impl std::fmt::Display for GenericParamList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Visibility {
+impl std::fmt::Display for IdentPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ItemList {
+impl std::fmt::Display for IfExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Rename {
+impl std::fmt::Display for Impl {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for UseTree {
+impl std::fmt::Display for ImplTraitType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for UseTreeList {
+impl std::fmt::Display for IndexExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Abi {
+impl std::fmt::Display for InferType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for GenericParamList {
+impl std::fmt::Display for ItemList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for WhereClause {
+impl std::fmt::Display for Label {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for BlockExpr {
+impl std::fmt::Display for LetElse {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for SelfParam {
+impl std::fmt::Display for LetExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Param {
+impl std::fmt::Display for LetStmt {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RecordFieldList {
+impl std::fmt::Display for Lifetime {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TupleFieldList {
+impl std::fmt::Display for LifetimeArg {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RecordField {
+impl std::fmt::Display for LifetimeParam {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TupleField {
+impl std::fmt::Display for Literal {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for VariantList {
+impl std::fmt::Display for LiteralPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Variant {
+impl std::fmt::Display for LoopExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for AssocItemList {
+impl std::fmt::Display for MacroCall {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ExternItemList {
+impl std::fmt::Display for MacroDef {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ConstParam {
+impl std::fmt::Display for MacroEagerInput {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for LifetimeParam {
+impl std::fmt::Display for MacroExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TypeParam {
+impl std::fmt::Display for MacroItems {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for WherePred {
+impl std::fmt::Display for MacroPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Meta {
+impl std::fmt::Display for MacroRules {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ExprStmt {
+impl std::fmt::Display for MacroStmts {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for LetStmt {
+impl std::fmt::Display for MacroType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for LetElse {
+impl std::fmt::Display for MatchArm {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ArrayExpr {
+impl std::fmt::Display for MatchArmList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for AsmExpr {
+impl std::fmt::Display for MatchExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for AwaitExpr {
+impl std::fmt::Display for MatchGuard {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for BinExpr {
+impl std::fmt::Display for Meta {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for BreakExpr {
+impl std::fmt::Display for MethodCallExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for CallExpr {
+impl std::fmt::Display for Module {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for CastExpr {
+impl std::fmt::Display for Name {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ClosureExpr {
+impl std::fmt::Display for NameRef {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ContinueExpr {
+impl std::fmt::Display for NeverType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for FieldExpr {
+impl std::fmt::Display for OffsetOfExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ForExpr {
+impl std::fmt::Display for OrPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for FormatArgsExpr {
+impl std::fmt::Display for Param {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for IfExpr {
+impl std::fmt::Display for ParamList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for IndexExpr {
+impl std::fmt::Display for ParenExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Literal {
+impl std::fmt::Display for ParenPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for LoopExpr {
+impl std::fmt::Display for ParenType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MacroExpr {
+impl std::fmt::Display for Path {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MatchExpr {
+impl std::fmt::Display for PathExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MethodCallExpr {
+impl std::fmt::Display for PathPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for OffsetOfExpr {
+impl std::fmt::Display for PathSegment {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ParenExpr {
+impl std::fmt::Display for PathType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for PathExpr {
+impl std::fmt::Display for PrefixExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for PrefixExpr {
+impl std::fmt::Display for PtrType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
@@ -4866,162 +4866,162 @@ impl std::fmt::Display for RangeExpr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RecordExpr {
+impl std::fmt::Display for RangePat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RefExpr {
+impl std::fmt::Display for RecordExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ReturnExpr {
+impl std::fmt::Display for RecordExprField {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for BecomeExpr {
+impl std::fmt::Display for RecordExprFieldList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TryExpr {
+impl std::fmt::Display for RecordField {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TupleExpr {
+impl std::fmt::Display for RecordFieldList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for WhileExpr {
+impl std::fmt::Display for RecordPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for YieldExpr {
+impl std::fmt::Display for RecordPatField {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for YeetExpr {
+impl std::fmt::Display for RecordPatFieldList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for LetExpr {
+impl std::fmt::Display for RefExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for UnderscoreExpr {
+impl std::fmt::Display for RefPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for FormatArgsArg {
+impl std::fmt::Display for RefType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for StmtList {
+impl std::fmt::Display for Rename {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Label {
+impl std::fmt::Display for RestPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RecordExprFieldList {
+impl std::fmt::Display for RetType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RecordExprField {
+impl std::fmt::Display for ReturnExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ArgList {
+impl std::fmt::Display for SelfParam {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MatchArmList {
+impl std::fmt::Display for SlicePat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MatchArm {
+impl std::fmt::Display for SliceType {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MatchGuard {
+impl std::fmt::Display for SourceFile {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ArrayType {
+impl std::fmt::Display for Static {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for DynTraitType {
+impl std::fmt::Display for StmtList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for FnPtrType {
+impl std::fmt::Display for Struct {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ForType {
+impl std::fmt::Display for TokenTree {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ImplTraitType {
+impl std::fmt::Display for Trait {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for InferType {
+impl std::fmt::Display for TraitAlias {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MacroType {
+impl std::fmt::Display for TryExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for NeverType {
+impl std::fmt::Display for TupleExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ParenType {
+impl std::fmt::Display for TupleField {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for PtrType {
+impl std::fmt::Display for TupleFieldList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RefType {
+impl std::fmt::Display for TuplePat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for SliceType {
+impl std::fmt::Display for TupleStructPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
@@ -5031,97 +5031,97 @@ impl std::fmt::Display for TupleType {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TypeBound {
+impl std::fmt::Display for TypeAlias {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for IdentPat {
+impl std::fmt::Display for TypeArg {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for BoxPat {
+impl std::fmt::Display for TypeBound {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RestPat {
+impl std::fmt::Display for TypeBoundList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for LiteralPat {
+impl std::fmt::Display for TypeParam {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MacroPat {
+impl std::fmt::Display for UnderscoreExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for OrPat {
+impl std::fmt::Display for Union {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ParenPat {
+impl std::fmt::Display for Use {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for PathPat {
+impl std::fmt::Display for UseTree {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for WildcardPat {
+impl std::fmt::Display for UseTreeList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RangePat {
+impl std::fmt::Display for Variant {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RecordPat {
+impl std::fmt::Display for VariantList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RefPat {
+impl std::fmt::Display for Visibility {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for SlicePat {
+impl std::fmt::Display for WhereClause {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TuplePat {
+impl std::fmt::Display for WherePred {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for TupleStructPat {
+impl std::fmt::Display for WhileExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ConstBlockPat {
+impl std::fmt::Display for WildcardPat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RecordPatFieldList {
+impl std::fmt::Display for YeetExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for RecordPatField {
+impl std::fmt::Display for YieldExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs
index f5863e9efe0..651a8ebbf79 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs
@@ -7,16 +7,16 @@ use crate::{
 };
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Whitespace {
+pub struct Byte {
     pub(crate) syntax: SyntaxToken,
 }
-impl std::fmt::Display for Whitespace {
+impl std::fmt::Display for Byte {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(&self.syntax, f)
     }
 }
-impl AstToken for Whitespace {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == WHITESPACE }
+impl AstToken for Byte {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -28,16 +28,16 @@ impl AstToken for Whitespace {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Comment {
+pub struct ByteString {
     pub(crate) syntax: SyntaxToken,
 }
-impl std::fmt::Display for Comment {
+impl std::fmt::Display for ByteString {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(&self.syntax, f)
     }
 }
-impl AstToken for Comment {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == COMMENT }
+impl AstToken for ByteString {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE_STRING }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -49,16 +49,16 @@ impl AstToken for Comment {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct String {
+pub struct CString {
     pub(crate) syntax: SyntaxToken,
 }
-impl std::fmt::Display for String {
+impl std::fmt::Display for CString {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(&self.syntax, f)
     }
 }
-impl AstToken for String {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == STRING }
+impl AstToken for CString {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == C_STRING }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -70,16 +70,16 @@ impl AstToken for String {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ByteString {
+pub struct Char {
     pub(crate) syntax: SyntaxToken,
 }
-impl std::fmt::Display for ByteString {
+impl std::fmt::Display for Char {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(&self.syntax, f)
     }
 }
-impl AstToken for ByteString {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE_STRING }
+impl AstToken for Char {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == CHAR }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -91,16 +91,16 @@ impl AstToken for ByteString {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct CString {
+pub struct Comment {
     pub(crate) syntax: SyntaxToken,
 }
-impl std::fmt::Display for CString {
+impl std::fmt::Display for Comment {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(&self.syntax, f)
     }
 }
-impl AstToken for CString {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == C_STRING }
+impl AstToken for Comment {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == COMMENT }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -112,16 +112,16 @@ impl AstToken for CString {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct IntNumber {
+pub struct FloatNumber {
     pub(crate) syntax: SyntaxToken,
 }
-impl std::fmt::Display for IntNumber {
+impl std::fmt::Display for FloatNumber {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(&self.syntax, f)
     }
 }
-impl AstToken for IntNumber {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == INT_NUMBER }
+impl AstToken for FloatNumber {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FLOAT_NUMBER }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -133,16 +133,16 @@ impl AstToken for IntNumber {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct FloatNumber {
+pub struct Ident {
     pub(crate) syntax: SyntaxToken,
 }
-impl std::fmt::Display for FloatNumber {
+impl std::fmt::Display for Ident {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(&self.syntax, f)
     }
 }
-impl AstToken for FloatNumber {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == FLOAT_NUMBER }
+impl AstToken for Ident {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -154,16 +154,16 @@ impl AstToken for FloatNumber {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Char {
+pub struct IntNumber {
     pub(crate) syntax: SyntaxToken,
 }
-impl std::fmt::Display for Char {
+impl std::fmt::Display for IntNumber {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(&self.syntax, f)
     }
 }
-impl AstToken for Char {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == CHAR }
+impl AstToken for IntNumber {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == INT_NUMBER }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -175,16 +175,16 @@ impl AstToken for Char {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Byte {
+pub struct String {
     pub(crate) syntax: SyntaxToken,
 }
-impl std::fmt::Display for Byte {
+impl std::fmt::Display for String {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(&self.syntax, f)
     }
 }
-impl AstToken for Byte {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE }
+impl AstToken for String {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == STRING }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -196,16 +196,16 @@ impl AstToken for Byte {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Ident {
+pub struct Whitespace {
     pub(crate) syntax: SyntaxToken,
 }
-impl std::fmt::Display for Ident {
+impl std::fmt::Display for Whitespace {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(&self.syntax, f)
     }
 }
-impl AstToken for Ident {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT }
+impl AstToken for Whitespace {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == WHITESPACE }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests.rs b/src/tools/rust-analyzer/crates/syntax/src/tests.rs
index 5400071c4b6..439daa358a8 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/tests.rs
@@ -1,8 +1,3 @@
-#[cfg(not(feature = "in-rust-tree"))]
-mod ast_src;
-#[cfg(not(feature = "in-rust-tree"))]
-mod sourcegen_ast;
-
 use std::{
     fs,
     path::{Path, PathBuf},
@@ -82,7 +77,25 @@ fn reparse_fuzz_tests() {
 fn self_hosting_parsing() {
     let crates_dir = project_root().join("crates");
 
-    let mut files = ::sourcegen::list_rust_files(&crates_dir);
+    let mut files = Vec::new();
+    let mut work = vec![crates_dir.to_path_buf()];
+    while let Some(dir) = work.pop() {
+        for entry in dir.read_dir().unwrap() {
+            let entry = entry.unwrap();
+            let file_type = entry.file_type().unwrap();
+            let path = entry.path();
+            let file_name = &path.file_name().unwrap_or_default().to_str().unwrap_or_default();
+            let is_hidden = file_name.starts_with('.');
+            if !is_hidden {
+                if file_type.is_dir() {
+                    work.push(path);
+                } else if file_type.is_file() && file_name.ends_with(".rs") {
+                    files.push(path);
+                }
+            }
+        }
+    }
+
     files.retain(|path| {
         // Get all files which are not in the crates/syntax/test_data folder
         !path.components().any(|component| component.as_os_str() == "test_data")
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 8cf65d11c6c..c8d785f83e8 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -2,8 +2,8 @@
 use std::{iter, mem, ops::Not, str::FromStr, sync};
 
 use base_db::{
-    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
-    FileChange, FileSet, LangCrateOrigin, SourceDatabaseExt, SourceRoot, Version, VfsPath,
+    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, FileChange,
+    FileSet, LangCrateOrigin, SourceDatabaseExt, SourceRoot, Version, VfsPath,
 };
 use cfg::CfgOptions;
 use hir_expand::{
@@ -14,7 +14,7 @@ use hir_expand::{
     },
 };
 use rustc_hash::FxHashMap;
-use span::{FileId, FilePosition, FileRange, Span};
+use span::{Edition, FileId, FilePosition, FileRange, Span};
 use test_utils::{
     extract_range_or_offset, Fixture, FixtureWithProjectMeta, RangeOrOffset, CURSOR_MARKER,
     ESCAPED_CURSOR_MARKER,
@@ -137,7 +137,10 @@ impl ChangeFixture {
         let mut crate_deps = Vec::new();
         let mut default_crate_root: Option<FileId> = None;
         let mut default_cfg = CfgOptions::default();
-        let mut default_env = Env::new_for_test_fixture();
+        let mut default_env = Env::from_iter([(
+            String::from("__ra_is_test_fixture"),
+            String::from("__ra_is_test_fixture"),
+        )]);
 
         let mut file_set = FileSet::default();
         let mut current_source_root_kind = SourceRootKind::Local;
@@ -262,7 +265,10 @@ impl ChangeFixture {
                 None,
                 Default::default(),
                 Default::default(),
-                Env::new_for_test_fixture(),
+                Env::from_iter([(
+                    String::from("__ra_is_test_fixture"),
+                    String::from("__ra_is_test_fixture"),
+                )]),
                 false,
                 CrateOrigin::Lang(LangCrateOrigin::Core),
             );
@@ -298,7 +304,10 @@ impl ChangeFixture {
                 None,
                 Default::default(),
                 Default::default(),
-                Env::new_for_test_fixture(),
+                Env::from_iter([(
+                    String::from("__ra_is_test_fixture"),
+                    String::from("__ra_is_test_fixture"),
+                )]),
                 true,
                 CrateOrigin::Local { repo: None, name: None },
             );
@@ -393,7 +402,7 @@ pub fn mirror(input: TokenStream) -> TokenStream {
             .into(),
             ProcMacro {
                 name: "mirror".into(),
-                kind: ProcMacroKind::FuncLike,
+                kind: ProcMacroKind::Bang,
                 expander: sync::Arc::new(MirrorProcMacroExpander),
                 disabled: false,
             },
@@ -408,7 +417,7 @@ pub fn shorten(input: TokenStream) -> TokenStream {
             .into(),
             ProcMacro {
                 name: "shorten".into(),
-                kind: ProcMacroKind::FuncLike,
+                kind: ProcMacroKind::Bang,
                 expander: sync::Arc::new(ShortenProcMacroExpander),
                 disabled: false,
             },
diff --git a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
index f9b120772f0..c85efd432b0 100644
--- a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
@@ -13,6 +13,7 @@ doctest = false
 
 [dependencies]
 home = "0.5.4"
+camino.workspace = true
 
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs
index a77fed585af..b577723612d 100644
--- a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs
@@ -2,10 +2,9 @@
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-use std::{
-    env, iter,
-    path::{Path, PathBuf},
-};
+use std::{env, iter, path::PathBuf};
+
+use camino::{Utf8Path, Utf8PathBuf};
 
 #[derive(Copy, Clone)]
 pub enum Tool {
@@ -16,7 +15,7 @@ pub enum Tool {
 }
 
 impl Tool {
-    pub fn proxy(self) -> Option<PathBuf> {
+    pub fn proxy(self) -> Option<Utf8PathBuf> {
         cargo_proxy(self.name())
     }
 
@@ -33,7 +32,7 @@ impl Tool {
     ///      example: for cargo, this tries all paths in $PATH with appended `cargo`, returning the
     ///      first that exists
     /// 4) If all else fails, we just try to use the executable name directly
-    pub fn prefer_proxy(self) -> PathBuf {
+    pub fn prefer_proxy(self) -> Utf8PathBuf {
         invoke(&[cargo_proxy, lookup_as_env_var, lookup_in_path], self.name())
     }
 
@@ -50,11 +49,11 @@ impl Tool {
     ///      example: for cargo, this tries $CARGO_HOME/bin/cargo, or ~/.cargo/bin/cargo if $CARGO_HOME is unset.
     ///      It seems that this is a reasonable place to try for cargo, rustc, and rustup
     /// 4) If all else fails, we just try to use the executable name directly
-    pub fn path(self) -> PathBuf {
+    pub fn path(self) -> Utf8PathBuf {
         invoke(&[lookup_as_env_var, lookup_in_path, cargo_proxy], self.name())
     }
 
-    pub fn path_in(self, path: &Path) -> Option<PathBuf> {
+    pub fn path_in(self, path: &Utf8Path) -> Option<Utf8PathBuf> {
         probe_for_binary(path.join(self.name()))
     }
 
@@ -68,42 +67,50 @@ impl Tool {
     }
 }
 
-fn invoke(list: &[fn(&str) -> Option<PathBuf>], executable: &str) -> PathBuf {
+fn invoke(list: &[fn(&str) -> Option<Utf8PathBuf>], executable: &str) -> Utf8PathBuf {
     list.iter().find_map(|it| it(executable)).unwrap_or_else(|| executable.into())
 }
 
 /// Looks up the binary as its SCREAMING upper case in the env variables.
-fn lookup_as_env_var(executable_name: &str) -> Option<PathBuf> {
-    env::var_os(executable_name.to_ascii_uppercase()).map(Into::into)
+fn lookup_as_env_var(executable_name: &str) -> Option<Utf8PathBuf> {
+    env::var_os(executable_name.to_ascii_uppercase())
+        .map(PathBuf::from)
+        .map(Utf8PathBuf::try_from)
+        .and_then(Result::ok)
 }
 
 /// Looks up the binary in the cargo home directory if it exists.
-fn cargo_proxy(executable_name: &str) -> Option<PathBuf> {
+fn cargo_proxy(executable_name: &str) -> Option<Utf8PathBuf> {
     let mut path = get_cargo_home()?;
     path.push("bin");
     path.push(executable_name);
     probe_for_binary(path)
 }
 
-fn get_cargo_home() -> Option<PathBuf> {
+fn get_cargo_home() -> Option<Utf8PathBuf> {
     if let Some(path) = env::var_os("CARGO_HOME") {
-        return Some(path.into());
+        return Utf8PathBuf::try_from(PathBuf::from(path)).ok();
     }
 
     if let Some(mut path) = home::home_dir() {
         path.push(".cargo");
-        return Some(path);
+        return Utf8PathBuf::try_from(path).ok();
     }
 
     None
 }
 
-fn lookup_in_path(exec: &str) -> Option<PathBuf> {
+fn lookup_in_path(exec: &str) -> Option<Utf8PathBuf> {
     let paths = env::var_os("PATH").unwrap_or_default();
-    env::split_paths(&paths).map(|path| path.join(exec)).find_map(probe_for_binary)
+    env::split_paths(&paths)
+        .map(|path| path.join(exec))
+        .map(PathBuf::from)
+        .map(Utf8PathBuf::try_from)
+        .filter_map(Result::ok)
+        .find_map(probe_for_binary)
 }
 
-pub fn probe_for_binary(path: PathBuf) -> Option<PathBuf> {
+pub fn probe_for_binary(path: Utf8PathBuf) -> Option<Utf8PathBuf> {
     let with_extension = match env::consts::EXE_EXTENSION {
         "" => None,
         it => Some(path.with_extension(it)),
diff --git a/src/tools/rust-analyzer/crates/tt/Cargo.toml b/src/tools/rust-analyzer/crates/tt/Cargo.toml
index 77683fd48af..c96f088cdc5 100644
--- a/src/tools/rust-analyzer/crates/tt/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/tt/Cargo.toml
@@ -17,8 +17,5 @@ text-size.workspace = true
 
 stdx.workspace = true
 
-# FIXME: Remove this dependency once the `Span` trait is gone (that is once Span::DUMMY has been removed)
-span.workspace = true
-
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs
index 28289a6431e..ab0efff6512 100644
--- a/src/tools/rust-analyzer/crates/tt/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs
@@ -11,18 +11,13 @@ use stdx::impl_from;
 pub use smol_str::SmolStr;
 pub use text_size::{TextRange, TextSize};
 
-pub trait Span: std::fmt::Debug + Copy + Sized + Eq {}
-
-impl<Ctx> Span for span::SpanData<Ctx> where span::SpanData<Ctx>: std::fmt::Debug + Copy + Sized + Eq
-{}
-
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum TokenTree<S> {
     Leaf(Leaf<S>),
     Subtree(Subtree<S>),
 }
 impl_from!(Leaf<S>, Subtree<S> for TokenTree);
-impl<S: Span> TokenTree<S> {
+impl<S: Copy> TokenTree<S> {
     pub fn empty(span: S) -> Self {
         Self::Subtree(Subtree {
             delimiter: Delimiter::invisible_spanned(span),
@@ -72,7 +67,7 @@ pub struct Subtree<S> {
     pub token_trees: Box<[TokenTree<S>]>,
 }
 
-impl<S: Span> Subtree<S> {
+impl<S: Copy> Subtree<S> {
     pub fn empty(span: DelimSpan<S>) -> Self {
         Subtree { delimiter: Delimiter::invisible_delim_spanned(span), token_trees: Box::new([]) }
     }
@@ -114,7 +109,7 @@ pub struct Delimiter<S> {
     pub kind: DelimiterKind,
 }
 
-impl<S: Span> Delimiter<S> {
+impl<S: Copy> Delimiter<S> {
     pub const fn invisible_spanned(span: S) -> Self {
         Delimiter { open: span, close: span, kind: DelimiterKind::Invisible }
     }
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 15a0ea5409a..4cfdec2b5c5 100644
--- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
@@ -136,7 +136,7 @@ impl NotifyActor {
                     Message::Invalidate(path) => {
                         let contents = read(path.as_path());
                         let files = vec![(path, contents)];
-                        self.send(loader::Message::Loaded { files });
+                        self.send(loader::Message::Changed { files });
                     }
                 },
                 Event::NotifyEvent(event) => {
@@ -205,7 +205,7 @@ impl NotifyActor {
                             if !entry.file_type().is_dir() {
                                 return true;
                             }
-                            let path = AbsPath::assert(entry.path());
+                            let path = entry.path();
                             root == path
                                 || dirs.exclude.iter().chain(&dirs.include).all(|it| it != path)
                         });
@@ -214,7 +214,7 @@ impl NotifyActor {
                         let depth = entry.depth();
                         let is_dir = entry.file_type().is_dir();
                         let is_file = entry.file_type().is_file();
-                        let abs_path = AbsPathBuf::assert(entry.into_path());
+                        let abs_path = AbsPathBuf::try_from(entry.into_path()).unwrap();
                         if depth < 2 && is_dir {
                             self.send(make_message(abs_path.clone()));
                         }
diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
index 824ce398703..ddd6bbe3f7a 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
@@ -91,12 +91,21 @@ impl nohash_hasher::IsEnabled for FileId {}
 pub struct Vfs {
     interner: PathInterner,
     data: Vec<FileState>,
+    // FIXME: This should be a HashMap<FileId, ChangeFile>
+    // right now we do a nasty deduplication in GlobalState::process_changes that would be a lot
+    // easier to handle here on insertion.
     changes: Vec<ChangedFile>,
+    // The above FIXME would then also get rid of this probably
+    created_this_cycle: Vec<FileId>,
 }
 
-#[derive(Copy, PartialEq, PartialOrd, Clone)]
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
 pub enum FileState {
+    /// The file has been created this cycle.
+    Created,
+    /// The file exists.
     Exists,
+    /// The file is deleted.
     Deleted,
 }
 
@@ -121,6 +130,16 @@ impl ChangedFile {
         matches!(self.change, Change::Create(_) | Change::Delete)
     }
 
+    /// Returns `true` if the change is [`Create`](ChangeKind::Create).
+    pub fn is_created(&self) -> bool {
+        matches!(self.change, Change::Create(_))
+    }
+
+    /// Returns `true` if the change is [`Modify`](ChangeKind::Modify).
+    pub fn is_modified(&self) -> bool {
+        matches!(self.change, Change::Modify(_))
+    }
+
     pub fn kind(&self) -> ChangeKind {
         match self.change {
             Change::Create(_) => ChangeKind::Create,
@@ -155,7 +174,9 @@ pub enum ChangeKind {
 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))
+        self.interner
+            .get(path)
+            .filter(|&it| matches!(self.get(it), FileState::Exists | FileState::Created))
     }
 
     /// File path corresponding to the given `file_id`.
@@ -173,7 +194,9 @@ impl Vfs {
     pub fn iter(&self) -> impl Iterator<Item = (FileId, &VfsPath)> + '_ {
         (0..self.data.len())
             .map(|it| FileId(it as u32))
-            .filter(move |&file_id| matches!(self.get(file_id), FileState::Exists))
+            .filter(move |&file_id| {
+                matches!(self.get(file_id), FileState::Exists | FileState::Created)
+            })
             .map(move |file_id| {
                 let path = self.interner.lookup(file_id);
                 (file_id, path)
@@ -188,27 +211,43 @@ impl Vfs {
     /// [`FileId`] for it.
     pub fn set_file_contents(&mut self, path: VfsPath, contents: Option<Vec<u8>>) -> bool {
         let file_id = self.alloc_file_id(path);
-        let change_kind = match (self.get(file_id), contents) {
+        let state = self.get(file_id);
+        let change_kind = match (state, contents) {
             (FileState::Deleted, None) => return false,
             (FileState::Deleted, Some(v)) => Change::Create(v),
-            (FileState::Exists, None) => Change::Delete,
-            (FileState::Exists, Some(v)) => Change::Modify(v),
+            (FileState::Exists | FileState::Created, None) => Change::Delete,
+            (FileState::Exists | FileState::Created, Some(v)) => Change::Modify(v),
+        };
+        self.data[file_id.0 as usize] = match change_kind {
+            Change::Create(_) => {
+                self.created_this_cycle.push(file_id);
+                FileState::Created
+            }
+            // If the file got created this cycle, make sure we keep it that way even
+            // if a modify comes in
+            Change::Modify(_) if matches!(state, FileState::Created) => FileState::Created,
+            Change::Modify(_) => FileState::Exists,
+            Change::Delete => FileState::Deleted,
         };
         let changed_file = ChangedFile { file_id, change: change_kind };
-        self.data[file_id.0 as usize] =
-            if changed_file.exists() { FileState::Exists } else { FileState::Deleted };
         self.changes.push(changed_file);
         true
     }
 
     /// Drain and returns all the changes in the `Vfs`.
     pub fn take_changes(&mut self) -> Vec<ChangedFile> {
+        for file_id in self.created_this_cycle.drain(..) {
+            if self.data[file_id.0 as usize] == FileState::Created {
+                // downgrade the file from `Created` to `Exists` as the cycle is done
+                self.data[file_id.0 as usize] = FileState::Exists;
+            }
+        }
         mem::take(&mut self.changes)
     }
 
     /// Provides a panic-less way to verify file_id validity.
     pub fn exists(&self, file_id: FileId) -> bool {
-        matches!(self.get(file_id), FileState::Exists)
+        matches!(self.get(file_id), FileState::Exists | FileState::Created)
     }
 
     /// Returns the id associated with `path`
diff --git a/src/tools/rust-analyzer/crates/vfs/src/loader.rs b/src/tools/rust-analyzer/crates/vfs/src/loader.rs
index c3d1ff7271a..3af91b1af81 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/loader.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/loader.rs
@@ -58,7 +58,7 @@ pub enum Message {
         /// The [`Config`] version.
         config_version: u32,
     },
-    /// The handle loaded the following files' content.
+    /// The handle loaded the following files' content for the first time.
     Loaded { files: Vec<(AbsPathBuf, Option<Vec<u8>>)> },
     /// The handle loaded the following files' content.
     Changed { files: Vec<(AbsPathBuf, Option<Vec<u8>>)> },
diff --git a/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs b/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs
index 52ada32bdfd..2d3fb9d88c8 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs
@@ -326,7 +326,7 @@ impl VirtualPath {
     }
 
     fn strip_prefix(&self, base: &VirtualPath) -> Option<&RelPath> {
-        <_ as AsRef<std::path::Path>>::as_ref(&self.0)
+        <_ as AsRef<paths::Utf8Path>>::as_ref(&self.0)
             .strip_prefix(&base.0)
             .ok()
             .map(RelPath::new_unchecked)
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index cf9ad5fe04d..939b1819c7e 100644
--- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp/ext.rs hash: 61f485497d6e8e88
+lsp/ext.rs hash: 223f48a89a5126a0
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
@@ -417,7 +417,7 @@ interface TestItem {
     // A human readable name for this test
     label: string;
     // The kind of this test item. Based on the kind,
-	// an icon is chosen by the editor. 
+	// an icon is chosen by the editor.
     kind: "package" | "module" | "test";
     // True if this test may have children not available eagerly
     canResolveChildren: boolean;
@@ -440,7 +440,11 @@ interface DiscoverTestResults {
     // For each test which its id is in this list, the response
     // contains all tests that are children of this test, and
     // client should remove old tests not included in the response.
-    scope: string[];
+    scope: string[] | undefined;
+    // For each file which its uri is in this list, the response
+    // contains all tests that are located in this file, and
+    // client should remove old tests not included in the response.
+    scopeFile: lc.TextDocumentIdentifier[] | undefined;    
 }
 ```
 
@@ -492,9 +496,9 @@ a `experimental/endRunTest` when is done.
 **Notification:** `ChangeTestStateParams`
 
 ```typescript
-type TestState = { tag: "passed" } 
+type TestState = { tag: "passed" }
     | {
-        tag: "failed"; 
+        tag: "failed";
         // The standard error of the test, containing the panic message. Clients should
         // render it similar to a terminal, and e.g. handle ansi colors.
         message: string;
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index 5e782b78311..c4024f6d282 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -520,6 +520,11 @@ How to render the offset information in a memory layout hover.
 --
 How to render the size information in a memory layout hover.
 --
+[[rust-analyzer.hover.show.structFields]]rust-analyzer.hover.show.structFields (default: `null`)::
++
+--
+How many fields of a struct to display when hovering a struct.
+--
 [[rust-analyzer.hover.show.traitAssocItems]]rust-analyzer.hover.show.traitAssocItems (default: `null`)::
 +
 --
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index c34b8e25de0..c3ea1ceeb69 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -1144,6 +1144,15 @@
                         }
                     ]
                 },
+                "rust-analyzer.hover.show.structFields": {
+                    "markdownDescription": "How many fields of a struct to display when hovering a struct.",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "integer"
+                    ],
+                    "minimum": 0
+                },
                 "rust-analyzer.hover.show.traitAssocItems": {
                     "markdownDescription": "How many associated items of a trait to display when hovering a trait.",
                     "default": null,
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index 92a816bfbcb..e676bc0826c 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -19,7 +19,7 @@ export class Config {
     configureLang: vscode.Disposable | undefined;
 
     readonly rootSection = "rust-analyzer";
-    private readonly requiresReloadOpts = [
+    private readonly requiresServerReloadOpts = [
         "cargo",
         "procMacro",
         "serverPath",
@@ -27,6 +27,10 @@ export class Config {
         "files",
     ].map((opt) => `${this.rootSection}.${opt}`);
 
+    private readonly requiresWindowReloadOpts = ["testExplorer"].map(
+        (opt) => `${this.rootSection}.${opt}`,
+    );
+
     readonly package: {
         version: string;
         releaseTag: string | null;
@@ -66,18 +70,31 @@ export class Config {
 
         this.configureLanguage();
 
-        const requiresReloadOpt = this.requiresReloadOpts.find((opt) =>
+        const requiresWindowReloadOpt = this.requiresWindowReloadOpts.find((opt) =>
+            event.affectsConfiguration(opt),
+        );
+
+        if (requiresWindowReloadOpt) {
+            const message = `Changing "${requiresWindowReloadOpt}" requires a window reload`;
+            const userResponse = await vscode.window.showInformationMessage(message, "Reload now");
+
+            if (userResponse) {
+                await vscode.commands.executeCommand("workbench.action.reloadWindow");
+            }
+        }
+
+        const requiresServerReloadOpt = this.requiresServerReloadOpts.find((opt) =>
             event.affectsConfiguration(opt),
         );
 
-        if (!requiresReloadOpt) return;
+        if (!requiresServerReloadOpt) return;
 
         if (this.restartServerOnConfigChange) {
             await vscode.commands.executeCommand("rust-analyzer.restartServer");
             return;
         }
 
-        const message = `Changing "${requiresReloadOpt}" requires a server restart`;
+        const message = `Changing "${requiresServerReloadOpt}" requires a server restart`;
         const userResponse = await vscode.window.showInformationMessage(message, "Restart now");
 
         if (userResponse) {
diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts
index 3fc63fc7d81..bad1f48de85 100644
--- a/src/tools/rust-analyzer/editors/code/src/debug.ts
+++ b/src/tools/rust-analyzer/editors/code/src/debug.ts
@@ -81,8 +81,8 @@ async function getDebugConfiguration(
     if (!editor) return;
 
     const knownEngines: Record<string, DebugConfigProvider> = {
-        "ms-vscode.cpptools": getCCppDebugConfig,
         "vadimcn.vscode-lldb": getCodeLldbDebugConfig,
+        "ms-vscode.cpptools": getCCppDebugConfig,
         "webfreak.debug": getNativeDebugConfig,
     };
     const debugOptions = ctx.config.debug;
@@ -203,6 +203,10 @@ function getCCppDebugConfig(
         cwd: cargoWorkspace || runnable.args.workspaceRoot,
         sourceFileMap,
         env,
+        // See https://github.com/rust-lang/rust-analyzer/issues/16901#issuecomment-2024486941
+        osx: {
+            MIMode: "lldb",
+        },
     };
 }
 
diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
index ca8106371b0..9a7a4aae959 100644
--- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
+++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
@@ -83,7 +83,11 @@ export type TestItem = {
     range?: lc.Range | undefined;
     runnable?: Runnable | undefined;
 };
-export type DiscoverTestResults = { tests: TestItem[]; scope: string[] };
+export type DiscoverTestResults = {
+    tests: TestItem[];
+    scope: string[] | undefined;
+    scopeFile: lc.TextDocumentIdentifier[] | undefined;
+};
 export type TestState =
     | { tag: "failed"; message: string }
     | { tag: "passed" }
diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts
index fc3f1acce54..02ccbb6956a 100644
--- a/src/tools/rust-analyzer/editors/code/src/run.ts
+++ b/src/tools/rust-analyzer/editors/code/src/run.ts
@@ -2,6 +2,7 @@ import * as vscode from "vscode";
 import type * as lc from "vscode-languageclient";
 import * as ra from "./lsp_ext";
 import * as tasks from "./tasks";
+import * as toolchain from "./toolchain";
 
 import type { CtxInit } from "./ctx";
 import { makeDebugConfig } from "./debug";
@@ -111,12 +112,22 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise
         throw `Unexpected runnable kind: ${runnable.kind}`;
     }
 
-    const args = createArgs(runnable);
+    let program: string;
+    let args = createArgs(runnable);
+    if (runnable.args.overrideCargo) {
+        // Split on spaces to allow overrides like "wrapper cargo".
+        const cargoParts = runnable.args.overrideCargo.split(" ");
 
-    const definition: tasks.CargoTaskDefinition = {
+        program = unwrapUndefinable(cargoParts[0]);
+        args = [...cargoParts.slice(1), ...args];
+    } else {
+        program = await toolchain.cargoPath();
+    }
+
+    const definition: tasks.RustTargetDefinition = {
         type: tasks.TASK_TYPE,
-        command: args[0], // run, test, etc...
-        args: args.slice(1),
+        program,
+        args,
         cwd: runnable.args.workspaceRoot || ".",
         env: prepareEnv(runnable, config.runnablesExtraEnv),
         overrideCargo: runnable.args.overrideCargo,
@@ -124,22 +135,21 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise
 
     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
     const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate()
-    const cargoTask = await tasks.buildCargoTask(
+    const task = await tasks.buildRustTask(
         target,
         definition,
         runnable.label,
-        args,
         config.problemMatcher,
         config.cargoRunner,
         true,
     );
 
-    cargoTask.presentationOptions.clear = true;
+    task.presentationOptions.clear = true;
     // Sadly, this doesn't prevent focus stealing if the terminal is currently
     // hidden, and will become revealed due to task execution.
-    cargoTask.presentationOptions.focus = false;
+    task.presentationOptions.focus = false;
 
-    return cargoTask;
+    return task;
 }
 
 export function createArgs(runnable: ra.Runnable): string[] {
diff --git a/src/tools/rust-analyzer/editors/code/src/tasks.ts b/src/tools/rust-analyzer/editors/code/src/tasks.ts
index 1d5ab82aa04..89abb37b0eb 100644
--- a/src/tools/rust-analyzer/editors/code/src/tasks.ts
+++ b/src/tools/rust-analyzer/editors/code/src/tasks.ts
@@ -2,22 +2,20 @@ import * as vscode from "vscode";
 import * as toolchain from "./toolchain";
 import type { Config } from "./config";
 import { log } from "./util";
-import { unwrapUndefinable } from "./undefinable";
 
 // This ends up as the `type` key in tasks.json. RLS also uses `cargo` and
 // our configuration should be compatible with it so use the same key.
 export const TASK_TYPE = "cargo";
 export const TASK_SOURCE = "rust";
 
-export interface CargoTaskDefinition extends vscode.TaskDefinition {
-    command?: string;
-    args?: string[];
+export interface RustTargetDefinition extends vscode.TaskDefinition {
+    program: string;
+    args: string[];
     cwd?: string;
     env?: { [key: string]: string };
-    overrideCargo?: string;
 }
 
-class CargoTaskProvider implements vscode.TaskProvider {
+class RustTaskProvider implements vscode.TaskProvider {
     private readonly config: Config;
 
     constructor(config: Config) {
@@ -39,14 +37,15 @@ class CargoTaskProvider implements vscode.TaskProvider {
             { command: "run", group: undefined },
         ];
 
+        const cargoPath = await toolchain.cargoPath();
+
         const tasks: vscode.Task[] = [];
         for (const workspaceTarget of vscode.workspace.workspaceFolders || []) {
             for (const def of defs) {
-                const vscodeTask = await buildCargoTask(
+                const vscodeTask = await buildRustTask(
                     workspaceTarget,
-                    { type: TASK_TYPE, command: def.command },
+                    { type: TASK_TYPE, program: cargoPath, args: [def.command] },
                     `cargo ${def.command}`,
-                    [def.command],
                     this.config.problemMatcher,
                     this.config.cargoRunner,
                 );
@@ -63,15 +62,13 @@ class CargoTaskProvider implements vscode.TaskProvider {
         // we need to inform VSCode how to execute that command by creating
         // a ShellExecution for it.
 
-        const definition = task.definition as CargoTaskDefinition;
+        const definition = task.definition as RustTargetDefinition;
 
-        if (definition.type === TASK_TYPE && definition.command) {
-            const args = [definition.command].concat(definition.args ?? []);
-            return await buildCargoTask(
+        if (definition.type === TASK_TYPE) {
+            return await buildRustTask(
                 task.scope,
                 definition,
                 task.name,
-                args,
                 this.config.problemMatcher,
                 this.config.cargoRunner,
             );
@@ -81,11 +78,10 @@ class CargoTaskProvider implements vscode.TaskProvider {
     }
 }
 
-export async function buildCargoTask(
+export async function buildRustTask(
     scope: vscode.WorkspaceFolder | vscode.TaskScope | undefined,
-    definition: CargoTaskDefinition,
+    definition: RustTargetDefinition,
     name: string,
-    args: string[],
     problemMatcher: string[],
     customRunner?: string,
     throwOnError: boolean = false,
@@ -95,7 +91,12 @@ export async function buildCargoTask(
     if (customRunner) {
         const runnerCommand = `${customRunner}.buildShellExecution`;
         try {
-            const runnerArgs = { kind: TASK_TYPE, args, cwd: definition.cwd, env: definition.env };
+            const runnerArgs = {
+                kind: TASK_TYPE,
+                args: definition.args,
+                cwd: definition.cwd,
+                env: definition.env,
+            };
             const customExec = await vscode.commands.executeCommand(runnerCommand, runnerArgs);
             if (customExec) {
                 if (customExec instanceof vscode.ShellExecution) {
@@ -113,16 +114,7 @@ export async function buildCargoTask(
     }
 
     if (!exec) {
-        // Check whether we must use a user-defined substitute for cargo.
-        // Split on spaces to allow overrides like "wrapper cargo".
-        const overrideCargo = definition.overrideCargo ?? definition.overrideCargo;
-        const cargoPath = await toolchain.cargoPath();
-        const cargoCommand = overrideCargo?.split(" ") ?? [cargoPath];
-
-        const fullCommand = [...cargoCommand, ...args];
-
-        const processName = unwrapUndefinable(fullCommand[0]);
-        exec = new vscode.ProcessExecution(processName, fullCommand.slice(1), definition);
+        exec = new vscode.ProcessExecution(definition.program, definition.args, definition);
     }
 
     return new vscode.Task(
@@ -138,6 +130,6 @@ export async function buildCargoTask(
 }
 
 export function activateTaskProvider(config: Config): vscode.Disposable {
-    const provider = new CargoTaskProvider(config);
+    const provider = new RustTaskProvider(config);
     return vscode.tasks.registerTaskProvider(TASK_TYPE, provider);
 }
diff --git a/src/tools/rust-analyzer/editors/code/src/test_explorer.ts b/src/tools/rust-analyzer/editors/code/src/test_explorer.ts
index ac4ffb19263..de41d2a57ec 100644
--- a/src/tools/rust-analyzer/editors/code/src/test_explorer.ts
+++ b/src/tools/rust-analyzer/editors/code/src/test_explorer.ts
@@ -12,6 +12,7 @@ export const prepareTestExplorer = (
 ) => {
     let currentTestRun: vscode.TestRun | undefined;
     let idToTestMap: Map<string, vscode.TestItem> = new Map();
+    const fileToTestMap: Map<string, vscode.TestItem[]> = new Map();
     const idToRunnableMap: Map<string, ra.Runnable> = new Map();
 
     testController.createRunProfile(
@@ -59,6 +60,18 @@ export const prepareTestExplorer = (
         false,
     );
 
+    const deleteTest = (item: vscode.TestItem, parentList: vscode.TestItemCollection) => {
+        parentList.delete(item.id);
+        idToTestMap.delete(item.id);
+        idToRunnableMap.delete(item.id);
+        if (item.uri) {
+            fileToTestMap.set(
+                item.uri.toString(),
+                fileToTestMap.get(item.uri.toString())!.filter((t) => t.id !== item.id),
+            );
+        }
+    };
+
     const addTest = (item: ra.TestItem) => {
         const parentList = item.parent
             ? idToTestMap.get(item.parent)!.children
@@ -76,7 +89,7 @@ export const prepareTestExplorer = (
                 oldTest.range = range;
                 return;
             }
-            parentList.delete(item.id);
+            deleteTest(oldTest, parentList);
         }
         const iconToVscodeMap = {
             package: "package",
@@ -91,6 +104,12 @@ export const prepareTestExplorer = (
         test.range = range;
         test.canResolveChildren = item.canResolveChildren;
         idToTestMap.set(item.id, test);
+        if (uri) {
+            if (!fileToTestMap.has(uri.toString())) {
+                fileToTestMap.set(uri.toString(), []);
+            }
+            fileToTestMap.get(uri.toString())!.push(test);
+        }
         if (item.runnable) {
             idToRunnableMap.set(item.id, item.runnable);
         }
@@ -98,33 +117,47 @@ export const prepareTestExplorer = (
     };
 
     const addTestGroup = (testsAndScope: ra.DiscoverTestResults) => {
-        const { tests, scope } = testsAndScope;
+        const { tests, scope, scopeFile } = testsAndScope;
         const testSet: Set<string> = new Set();
         for (const test of tests) {
             addTest(test);
             testSet.add(test.id);
         }
         // FIXME(hack_recover_crate_name): We eagerly resolve every test if we got a lazy top level response (detected
-        // by `!scope`). ctx is not a good thing and wastes cpu and memory unnecessarily, so we should remove it.
-        if (!scope) {
+        // by checking that `scope` is empty). This is not a good thing and wastes cpu and memory unnecessarily, so we
+        // should remove it.
+        if (!scope && !scopeFile) {
             for (const test of tests) {
                 void testController.resolveHandler!(idToTestMap.get(test.id));
             }
         }
-        if (!scope) {
-            return;
+        if (scope) {
+            const recursivelyRemove = (tests: vscode.TestItemCollection) => {
+                for (const [_, test] of tests) {
+                    if (!testSet.has(test.id)) {
+                        deleteTest(test, tests);
+                    } else {
+                        recursivelyRemove(test.children);
+                    }
+                }
+            };
+            for (const root of scope) {
+                recursivelyRemove(idToTestMap.get(root)!.children);
+            }
         }
-        const recursivelyRemove = (tests: vscode.TestItemCollection) => {
-            for (const [testId, _] of tests) {
-                if (!testSet.has(testId)) {
-                    tests.delete(testId);
-                } else {
-                    recursivelyRemove(tests.get(testId)!.children);
+        if (scopeFile) {
+            const removeByFile = (file: vscode.Uri) => {
+                const testsToBeRemoved = (fileToTestMap.get(file.toString()) || []).filter(
+                    (t) => !testSet.has(t.id),
+                );
+                for (const test of testsToBeRemoved) {
+                    const parentList = test.parent?.children || testController.items;
+                    deleteTest(test, parentList);
                 }
+            };
+            for (const file of scopeFile) {
+                removeByFile(vscode.Uri.parse(file.uri));
             }
-        };
-        for (const root of scope) {
-            recursivelyRemove(idToTestMap.get(root)!.children);
         }
     };
 
diff --git a/src/tools/rust-analyzer/xtask/Cargo.toml b/src/tools/rust-analyzer/xtask/Cargo.toml
index 5e758e0190c..a83d32e4141 100644
--- a/src/tools/rust-analyzer/xtask/Cargo.toml
+++ b/src/tools/rust-analyzer/xtask/Cargo.toml
@@ -15,6 +15,10 @@ xflags = "0.3.0"
 time = { version = "0.3", default-features = false }
 zip = { version = "0.6", default-features = false, features = ["deflate", "time"] }
 stdx.workspace = true
+proc-macro2 = "1.0.47"
+quote = "1.0.20"
+ungrammar = "1.16.1"
+itertools.workspace = true
 # Avoid adding more dependencies to this crate
 
 [lints]
diff --git a/src/tools/rust-analyzer/xtask/src/codegen.rs b/src/tools/rust-analyzer/xtask/src/codegen.rs
index 40f872a24ab..7dc1b40783c 100644
--- a/src/tools/rust-analyzer/xtask/src/codegen.rs
+++ b/src/tools/rust-analyzer/xtask/src/codegen.rs
@@ -9,6 +9,7 @@ use crate::{flags, project_root};
 
 pub(crate) mod assists_doc_tests;
 pub(crate) mod diagnostics_docs;
+mod grammar;
 mod lints;
 
 impl flags::Codegen {
@@ -20,6 +21,7 @@ impl flags::Codegen {
                 // lints::generate(self.check) Updating clones the rust repo, so don't run it unless
                 // explicitly asked for
             }
+            flags::CodegenType::Grammar => grammar::generate(self.check),
             flags::CodegenType::AssistsDocTests => assists_doc_tests::generate(self.check),
             flags::CodegenType::DiagnosticsDocs => diagnostics_docs::generate(self.check),
             flags::CodegenType::LintDefinitions => lints::generate(self.check),
diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs
index 2fd7a473498..cc2fadc9750 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs
@@ -3,37 +3,45 @@
 //! Specifically, it generates the `SyntaxKind` enum and a number of newtype
 //! wrappers around `SyntaxNode` which implement `syntax::AstNode`.
 
-use std::{collections::BTreeSet, fmt::Write};
+#![allow(clippy::disallowed_types)]
+
+use std::{
+    collections::{BTreeSet, HashSet},
+    fmt::Write,
+    fs,
+};
 
 use itertools::Itertools;
 use proc_macro2::{Punct, Spacing};
 use quote::{format_ident, quote};
-use rustc_hash::FxHashSet;
 use ungrammar::{Grammar, Rule};
 
-use crate::tests::ast_src::{
-    AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC,
+use crate::{
+    codegen::{add_preamble, ensure_file_contents, reformat},
+    project_root,
 };
 
-#[test]
-fn sourcegen_ast() {
+mod ast_src;
+use self::ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC};
+
+pub(crate) fn generate(check: bool) {
     let syntax_kinds = generate_syntax_kinds(KINDS_SRC);
-    let syntax_kinds_file =
-        sourcegen::project_root().join("crates/parser/src/syntax_kind/generated.rs");
-    sourcegen::ensure_file_contents(syntax_kinds_file.as_path(), &syntax_kinds);
+    let syntax_kinds_file = project_root().join("crates/parser/src/syntax_kind/generated.rs");
+    ensure_file_contents(syntax_kinds_file.as_path(), &syntax_kinds, check);
 
-    let grammar =
-        include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/rust.ungram")).parse().unwrap();
+    let grammar = fs::read_to_string(project_root().join("crates/syntax/rust.ungram"))
+        .unwrap()
+        .parse()
+        .unwrap();
     let ast = lower(&grammar);
 
     let ast_tokens = generate_tokens(&ast);
-    let ast_tokens_file =
-        sourcegen::project_root().join("crates/syntax/src/ast/generated/tokens.rs");
-    sourcegen::ensure_file_contents(ast_tokens_file.as_path(), &ast_tokens);
+    let ast_tokens_file = project_root().join("crates/syntax/src/ast/generated/tokens.rs");
+    ensure_file_contents(ast_tokens_file.as_path(), &ast_tokens, check);
 
     let ast_nodes = generate_nodes(KINDS_SRC, &ast);
-    let ast_nodes_file = sourcegen::project_root().join("crates/syntax/src/ast/generated/nodes.rs");
-    sourcegen::ensure_file_contents(ast_nodes_file.as_path(), &ast_nodes);
+    let ast_nodes_file = project_root().join("crates/syntax/src/ast/generated/nodes.rs");
+    ensure_file_contents(ast_nodes_file.as_path(), &ast_nodes, check);
 }
 
 fn generate_tokens(grammar: &AstSrc) -> String {
@@ -60,9 +68,9 @@ fn generate_tokens(grammar: &AstSrc) -> String {
         }
     });
 
-    sourcegen::add_preamble(
+    add_preamble(
         "sourcegen_ast",
-        sourcegen::reformat(
+        reformat(
             quote! {
                 use crate::{SyntaxKind::{self, *}, SyntaxToken, ast::AstToken};
                 #(#tokens)*
@@ -150,13 +158,14 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
         .enums
         .iter()
         .map(|en| {
-            let variants: Vec<_> = en.variants.iter().map(|var| format_ident!("{}", var)).collect();
+            let variants: Vec<_> =
+                en.variants.iter().map(|var| format_ident!("{}", var)).sorted().collect();
             let name = format_ident!("{}", en.name);
             let kinds: Vec<_> = variants
                 .iter()
                 .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
                 .collect();
-            let traits = en.traits.iter().map(|trait_name| {
+            let traits = en.traits.iter().sorted().map(|trait_name| {
                 let trait_name = format_ident!("{}", trait_name);
                 quote!(impl ast::#trait_name for #name {})
             });
@@ -212,14 +221,13 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
             )
         })
         .unzip();
-
     let (any_node_defs, any_node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
         .nodes
         .iter()
         .flat_map(|node| node.traits.iter().map(move |t| (t, node)))
         .into_group_map()
         .into_iter()
-        .sorted_by_key(|(k, _)| *k)
+        .sorted_by_key(|(name, _)| *name)
         .map(|(trait_name, nodes)| {
             let name = format_ident!("Any{}", trait_name);
             let trait_name = format_ident!("{}", trait_name);
@@ -276,7 +284,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
             }
         });
 
-    let defined_nodes: FxHashSet<_> = node_names.collect();
+    let defined_nodes: HashSet<_> = node_names.collect();
 
     for node in kinds
         .nodes
@@ -320,7 +328,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
         }
     }
 
-    let res = sourcegen::add_preamble("sourcegen_ast", sourcegen::reformat(res));
+    let res = add_preamble("sourcegen_ast", reformat(res));
     res.replace("#[derive", "\n#[derive")
 }
 
@@ -450,7 +458,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String {
         }
     };
 
-    sourcegen::add_preamble("sourcegen_ast", sourcegen::reformat(ast.to_string()))
+    add_preamble("sourcegen_ast", reformat(ast.to_string()))
 }
 
 fn to_upper_snake_case(s: &str) -> String {
@@ -600,6 +608,20 @@ fn lower(grammar: &Grammar) -> AstSrc {
     extract_enums(&mut res);
     extract_struct_traits(&mut res);
     extract_enum_traits(&mut res);
+    res.nodes.sort_by_key(|it| it.name.clone());
+    res.enums.sort_by_key(|it| it.name.clone());
+    res.tokens.sort();
+    res.nodes.iter_mut().for_each(|it| {
+        it.traits.sort();
+        it.fields.sort_by_key(|it| match it {
+            Field::Token(name) => (true, name.clone()),
+            Field::Node { name, .. } => (false, name.clone()),
+        });
+    });
+    res.enums.iter_mut().for_each(|it| {
+        it.traits.sort();
+        it.variants.sort();
+    });
     res
 }
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs
index 8221c577892..8221c577892 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs
+++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs
diff --git a/src/tools/rust-analyzer/xtask/src/dist.rs b/src/tools/rust-analyzer/xtask/src/dist.rs
index 7e54d19fe4d..2fe9db98cf2 100644
--- a/src/tools/rust-analyzer/xtask/src/dist.rs
+++ b/src/tools/rust-analyzer/xtask/src/dist.rs
@@ -10,7 +10,11 @@ use time::OffsetDateTime;
 use xshell::{cmd, Shell};
 use zip::{write::FileOptions, DateTime, ZipWriter};
 
-use crate::{date_iso, flags, project_root};
+use crate::{
+    date_iso,
+    flags::{self, Malloc},
+    project_root,
+};
 
 const VERSION_STABLE: &str = "0.3";
 const VERSION_NIGHTLY: &str = "0.4";
@@ -22,6 +26,7 @@ impl flags::Dist {
 
         let project_root = project_root();
         let target = Target::get(&project_root);
+        let allocator = self.allocator();
         let dist = project_root.join("dist");
         sh.remove_path(&dist)?;
         sh.create_dir(&dist)?;
@@ -33,11 +38,11 @@ impl flags::Dist {
                 // A hack to make VS Code prefer nightly over stable.
                 format!("{VERSION_NIGHTLY}.{patch_version}")
             };
-            dist_server(sh, &format!("{version}-standalone"), &target)?;
+            dist_server(sh, &format!("{version}-standalone"), &target, allocator)?;
             let release_tag = if stable { date_iso(sh)? } else { "nightly".to_owned() };
             dist_client(sh, &version, &release_tag, &target)?;
         } else {
-            dist_server(sh, "0.0.0-standalone", &target)?;
+            dist_server(sh, "0.0.0-standalone", &target, allocator)?;
         }
         Ok(())
     }
@@ -73,7 +78,12 @@ fn dist_client(
     Ok(())
 }
 
-fn dist_server(sh: &Shell, release: &str, target: &Target) -> anyhow::Result<()> {
+fn dist_server(
+    sh: &Shell,
+    release: &str,
+    target: &Target,
+    allocator: Malloc,
+) -> anyhow::Result<()> {
     let _e = sh.push_env("CFG_RELEASE", release);
     let _e = sh.push_env("CARGO_PROFILE_RELEASE_LTO", "thin");
 
@@ -87,7 +97,8 @@ fn dist_server(sh: &Shell, release: &str, target: &Target) -> anyhow::Result<()>
     }
 
     let target_name = &target.name;
-    cmd!(sh, "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} --release").run()?;
+    let features = allocator.to_features();
+    cmd!(sh, "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} {features...} --release").run()?;
 
     let dst = Path::new("dist").join(&target.artifact_name);
     gzip(&target.server_path, &dst.with_extension("gz"))?;
diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs
index 681c588bd01..90665459208 100644
--- a/src/tools/rust-analyzer/xtask/src/flags.rs
+++ b/src/tools/rust-analyzer/xtask/src/flags.rs
@@ -2,7 +2,7 @@
 
 use std::str::FromStr;
 
-use crate::install::{ClientOpt, Malloc, ServerOpt};
+use crate::install::{ClientOpt, ServerOpt};
 
 xflags::xflags! {
     src "./src/flags.rs"
@@ -36,6 +36,10 @@ xflags::xflags! {
             optional --dry-run
         }
         cmd dist {
+            /// Use mimalloc allocator for server
+            optional --mimalloc
+            /// Use jemalloc allocator for server
+            optional --jemalloc
             optional --client-patch-version version: String
         }
         /// Read a changelog AsciiDoc file and update the GitHub Releases entry in Markdown.
@@ -82,33 +86,6 @@ pub enum XtaskCmd {
 }
 
 #[derive(Debug)]
-pub struct Codegen {
-    pub check: bool,
-    pub codegen_type: Option<CodegenType>,
-}
-
-#[derive(Debug, Default)]
-pub enum CodegenType {
-    #[default]
-    All,
-    AssistsDocTests,
-    DiagnosticsDocs,
-    LintDefinitions,
-}
-
-impl FromStr for CodegenType {
-    type Err = String;
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "all" => Ok(Self::All),
-            "assists-doc-tests" => Ok(Self::AssistsDocTests),
-            "diagnostics-docs" => Ok(Self::DiagnosticsDocs),
-            "lints-definitions" => Ok(Self::LintDefinitions),
-            _ => Err("Invalid option".to_owned()),
-        }
-    }
-}
-#[derive(Debug)]
 pub struct Install {
     pub client: bool,
     pub code_bin: Option<String>,
@@ -133,6 +110,8 @@ pub struct Promote {
 
 #[derive(Debug)]
 pub struct Dist {
+    pub mimalloc: bool,
+    pub jemalloc: bool,
     pub client_patch_version: Option<String>,
 }
 
@@ -144,6 +123,65 @@ pub struct PublishReleaseNotes {
 }
 
 #[derive(Debug)]
+pub struct Metrics {
+    pub measurement_type: Option<MeasurementType>,
+}
+
+#[derive(Debug)]
+pub struct Bb {
+    pub suffix: String,
+}
+
+#[derive(Debug)]
+pub struct Codegen {
+    pub codegen_type: Option<CodegenType>,
+
+    pub check: bool,
+}
+
+impl Xtask {
+    #[allow(dead_code)]
+    pub fn from_env_or_exit() -> Self {
+        Self::from_env_or_exit_()
+    }
+
+    #[allow(dead_code)]
+    pub fn from_env() -> xflags::Result<Self> {
+        Self::from_env_()
+    }
+
+    #[allow(dead_code)]
+    pub fn from_vec(args: Vec<std::ffi::OsString>) -> xflags::Result<Self> {
+        Self::from_vec_(args)
+    }
+}
+// generated end
+
+#[derive(Debug, Default)]
+pub enum CodegenType {
+    #[default]
+    All,
+    Grammar,
+    AssistsDocTests,
+    DiagnosticsDocs,
+    LintDefinitions,
+}
+
+impl FromStr for CodegenType {
+    type Err = String;
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "all" => Ok(Self::All),
+            "grammar" => Ok(Self::Grammar),
+            "assists-doc-tests" => Ok(Self::AssistsDocTests),
+            "diagnostics-docs" => Ok(Self::DiagnosticsDocs),
+            "lints-definitions" => Ok(Self::LintDefinitions),
+            _ => Err("Invalid option".to_owned()),
+        }
+    }
+}
+
+#[derive(Debug)]
 pub enum MeasurementType {
     Build,
     RustcTests,
@@ -183,33 +221,22 @@ impl AsRef<str> for MeasurementType {
     }
 }
 
-#[derive(Debug)]
-pub struct Metrics {
-    pub measurement_type: Option<MeasurementType>,
-}
-
-#[derive(Debug)]
-pub struct Bb {
-    pub suffix: String,
+#[derive(Clone, Copy, Debug)]
+pub(crate) enum Malloc {
+    System,
+    Mimalloc,
+    Jemalloc,
 }
 
-impl Xtask {
-    #[allow(dead_code)]
-    pub fn from_env_or_exit() -> Self {
-        Self::from_env_or_exit_()
-    }
-
-    #[allow(dead_code)]
-    pub fn from_env() -> xflags::Result<Self> {
-        Self::from_env_()
-    }
-
-    #[allow(dead_code)]
-    pub fn from_vec(args: Vec<std::ffi::OsString>) -> xflags::Result<Self> {
-        Self::from_vec_(args)
+impl Malloc {
+    pub(crate) fn to_features(self) -> &'static [&'static str] {
+        match self {
+            Malloc::System => &[][..],
+            Malloc::Mimalloc => &["--features", "mimalloc"],
+            Malloc::Jemalloc => &["--features", "jemalloc"],
+        }
     }
 }
-// generated end
 
 impl Install {
     pub(crate) fn server(&self) -> Option<ServerOpt> {
@@ -232,3 +259,15 @@ impl Install {
         Some(ClientOpt { code_bin: self.code_bin.clone() })
     }
 }
+
+impl Dist {
+    pub(crate) fn allocator(&self) -> Malloc {
+        if self.mimalloc {
+            Malloc::Mimalloc
+        } else if self.jemalloc {
+            Malloc::Jemalloc
+        } else {
+            Malloc::System
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/xtask/src/install.rs b/src/tools/rust-analyzer/xtask/src/install.rs
index dc932da80c2..72e612f9e1d 100644
--- a/src/tools/rust-analyzer/xtask/src/install.rs
+++ b/src/tools/rust-analyzer/xtask/src/install.rs
@@ -5,7 +5,7 @@ use std::{env, path::PathBuf, str};
 use anyhow::{bail, format_err, Context};
 use xshell::{cmd, Shell};
 
-use crate::flags;
+use crate::flags::{self, Malloc};
 
 impl flags::Install {
     pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
@@ -34,12 +34,6 @@ pub(crate) struct ServerOpt {
     pub(crate) dev_rel: bool,
 }
 
-pub(crate) enum Malloc {
-    System,
-    Mimalloc,
-    Jemalloc,
-}
-
 fn fix_path_for_mac(sh: &Shell) -> anyhow::Result<()> {
     let mut vscode_path: Vec<PathBuf> = {
         const COMMON_APP_PATH: &str =
@@ -122,7 +116,7 @@ fn install_client(sh: &Shell, client_opt: ClientOpt) -> anyhow::Result<()> {
     if !installed_extensions.contains("rust-analyzer") {
         bail!(
             "Could not install the Visual Studio Code extension. \
-            Please make sure you have at least NodeJS 12.x together with the latest version of VS Code installed and try again. \
+            Please make sure you have at least NodeJS 16.x together with the latest version of VS Code installed and try again. \
             Note that installing via xtask install does not work for VS Code Remote, instead you’ll need to install the .vsix manually."
         );
     }
@@ -131,11 +125,7 @@ fn install_client(sh: &Shell, client_opt: ClientOpt) -> anyhow::Result<()> {
 }
 
 fn install_server(sh: &Shell, opts: ServerOpt) -> anyhow::Result<()> {
-    let features = match opts.malloc {
-        Malloc::System => &[][..],
-        Malloc::Mimalloc => &["--features", "mimalloc"],
-        Malloc::Jemalloc => &["--features", "jemalloc"],
-    };
+    let features = opts.malloc.to_features();
     let profile = if opts.dev_rel { "dev-rel" } else { "release" };
 
     let cmd = cmd!(sh, "cargo install --path crates/rust-analyzer --profile={profile} --locked --force --features force-always-assert {features...}");
diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs
index e5a925b2cbf..2f093e7ad17 100644
--- a/src/tools/rust-installer/src/tarballer.rs
+++ b/src/tools/rust-installer/src/tarballer.rs
@@ -2,7 +2,7 @@ use anyhow::{bail, Context, Result};
 use std::fs::{read_link, symlink_metadata};
 use std::io::{BufWriter, Write};
 use std::path::Path;
-use tar::{Builder, Header};
+use tar::{Builder, Header, HeaderMode};
 use walkdir::WalkDir;
 
 use crate::{
@@ -53,14 +53,19 @@ impl Tarballer {
         // Sort files by their suffix, to group files with the same name from
         // different locations (likely identical) and files with the same
         // extension (likely containing similar data).
-        let (dirs, mut files) = get_recursive_paths(&self.work_dir, &self.input)
+        // Sorting of file and directory paths also helps with the reproducibility
+        // of the resulting archive.
+        let (mut dirs, mut files) = get_recursive_paths(&self.work_dir, &self.input)
             .context("failed to collect file paths")?;
+        dirs.sort();
         files.sort_by(|a, b| a.bytes().rev().cmp(b.bytes().rev()));
 
         // Write the tar into both encoded files. We write all directories
         // first, so files may be directly created. (See rust-lang/rustup.rs#1092.)
         let buf = BufWriter::with_capacity(1024 * 1024, encoder);
         let mut builder = Builder::new(buf);
+        // Make uid, gid and mtime deterministic to improve reproducibility
+        builder.mode(HeaderMode::Deterministic);
 
         let pool = rayon::ThreadPoolBuilder::new().num_threads(2).build().unwrap();
         pool.install(move || {
@@ -91,7 +96,8 @@ impl Tarballer {
 fn append_path<W: Write>(builder: &mut Builder<W>, src: &Path, path: &String) -> Result<()> {
     let stat = symlink_metadata(src)?;
     let mut header = Header::new_gnu();
-    header.set_metadata(&stat);
+    header.set_metadata_in_mode(&stat, HeaderMode::Deterministic);
+
     if stat.file_type().is_symlink() {
         let link = read_link(src)?;
         builder.append_link(&mut header, path, &link)?;
diff --git a/src/tools/rustdoc-js/.eslintrc.js b/src/tools/rustdoc-js/.eslintrc.js
index 4ab3a315733..b9d0e251c24 100644
--- a/src/tools/rustdoc-js/.eslintrc.js
+++ b/src/tools/rustdoc-js/.eslintrc.js
@@ -6,7 +6,7 @@ module.exports = {
     },
     "extends": "eslint:recommended",
     "parserOptions": {
-        "ecmaVersion": 2015,
+        "ecmaVersion": 8,
         "sourceType": "module"
     },
     "rules": {
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index 86881ef362e..43a22f358c3 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -1,3 +1,4 @@
+/* global globalThis */
 const fs = require("fs");
 const path = require("path");
 
@@ -133,7 +134,7 @@ function valueCheck(fullPath, expected, result, error_text, queryName) {
                     expected_value,
                     result.get(key),
                     error_text,
-                    queryName
+                    queryName,
                 );
             } else {
                 error_text.push(`${queryName}==> EXPECTED has extra key in map from field ` +
@@ -212,11 +213,11 @@ function runParser(query, expected, parseQuery, queryName) {
     return error_text;
 }
 
-function runSearch(query, expected, doSearch, loadedFile, queryName) {
+async function runSearch(query, expected, doSearch, loadedFile, queryName) {
     const ignore_order = loadedFile.ignore_order;
     const exact_check = loadedFile.exact_check;
 
-    const results = doSearch(query, loadedFile.FILTER_CRATE);
+    const results = await doSearch(query, loadedFile.FILTER_CRATE);
     const error_text = [];
 
     for (const key in expected) {
@@ -238,7 +239,7 @@ function runSearch(query, expected, doSearch, loadedFile, queryName) {
         }
 
         let prev_pos = -1;
-        entry.forEach((elem, index) => {
+        for (const [index, elem] of entry.entries()) {
             const entry_pos = lookForEntry(elem, results[key]);
             if (entry_pos === -1) {
                 error_text.push(queryName + "==> Result not found in '" + key + "': '" +
@@ -260,13 +261,13 @@ function runSearch(query, expected, doSearch, loadedFile, queryName) {
             } else {
                 prev_pos = entry_pos;
             }
-        });
+        }
     }
     return error_text;
 }
 
-function runCorrections(query, corrections, getCorrections, loadedFile) {
-    const qc = getCorrections(query, loadedFile.FILTER_CRATE);
+async function runCorrections(query, corrections, getCorrections, loadedFile) {
+    const qc = await getCorrections(query, loadedFile.FILTER_CRATE);
     const error_text = [];
 
     if (corrections === null) {
@@ -299,18 +300,27 @@ function checkResult(error_text, loadedFile, displaySuccess) {
     return 1;
 }
 
-function runCheckInner(callback, loadedFile, entry, getCorrections, extra) {
+async function runCheckInner(callback, loadedFile, entry, getCorrections, extra) {
     if (typeof entry.query !== "string") {
         console.log("FAILED");
         console.log("==> Missing `query` field");
         return false;
     }
-    let error_text = callback(entry.query, entry, extra ? "[ query `" + entry.query + "`]" : "");
+    let error_text = await callback(
+        entry.query,
+        entry,
+        extra ? "[ query `" + entry.query + "`]" : "",
+    );
     if (checkResult(error_text, loadedFile, false) !== 0) {
         return false;
     }
     if (entry.correction !== undefined) {
-        error_text = runCorrections(entry.query, entry.correction, getCorrections, loadedFile);
+        error_text = await runCorrections(
+            entry.query,
+            entry.correction,
+            getCorrections,
+            loadedFile,
+        );
         if (checkResult(error_text, loadedFile, false) !== 0) {
             return false;
         }
@@ -318,16 +328,16 @@ function runCheckInner(callback, loadedFile, entry, getCorrections, extra) {
     return true;
 }
 
-function runCheck(loadedFile, key, getCorrections, callback) {
+async function runCheck(loadedFile, key, getCorrections, callback) {
     const expected = loadedFile[key];
 
     if (Array.isArray(expected)) {
         for (const entry of expected) {
-            if (!runCheckInner(callback, loadedFile, entry, getCorrections, true)) {
+            if (!await runCheckInner(callback, loadedFile, entry, getCorrections, true)) {
                 return 1;
             }
         }
-    } else if (!runCheckInner(callback, loadedFile, expected, getCorrections, false)) {
+    } else if (!await runCheckInner(callback, loadedFile, expected, getCorrections, false)) {
         return 1;
     }
     console.log("OK");
@@ -338,7 +348,7 @@ function hasCheck(content, checkName) {
     return content.startsWith(`const ${checkName}`) || content.includes(`\nconst ${checkName}`);
 }
 
-function runChecks(testFile, doSearch, parseQuery, getCorrections) {
+async function runChecks(testFile, doSearch, parseQuery, getCorrections) {
     let checkExpected = false;
     let checkParsed = false;
     let testFileContent = readFile(testFile);
@@ -367,12 +377,12 @@ function runChecks(testFile, doSearch, parseQuery, getCorrections) {
     let res = 0;
 
     if (checkExpected) {
-        res += runCheck(loadedFile, "EXPECTED", getCorrections, (query, expected, text) => {
+        res += await runCheck(loadedFile, "EXPECTED", getCorrections, (query, expected, text) => {
             return runSearch(query, expected, doSearch, loadedFile, text);
         });
     }
     if (checkParsed) {
-        res += runCheck(loadedFile, "PARSED", getCorrections, (query, expected, text) => {
+        res += await runCheck(loadedFile, "PARSED", getCorrections, (query, expected, text) => {
             return runParser(query, expected, parseQuery, text);
         });
     }
@@ -393,6 +403,35 @@ function loadSearchJS(doc_folder, resource_suffix) {
     const searchIndexJs = path.join(doc_folder, "search-index" + resource_suffix + ".js");
     const searchIndex = require(searchIndexJs);
 
+    globalThis.searchState = {
+        descShards: new Map(),
+        loadDesc: async function({descShard, descIndex}) {
+            if (descShard.promise === null) {
+                descShard.promise = new Promise((resolve, reject) => {
+                    descShard.resolve = resolve;
+                    const ds = descShard;
+                    const fname = `${ds.crate}-desc-${ds.shard}-${resource_suffix}.js`;
+                    fs.readFile(
+                        `${doc_folder}/search.desc/${descShard.crate}/${fname}`,
+                        (err, data) => {
+                            if (err) {
+                                reject(err);
+                            } else {
+                                eval(data.toString("utf8"));
+                            }
+                        },
+                    );
+                });
+            }
+            const list = await descShard.promise;
+            return list[descIndex];
+        },
+        loadedDescShard: function(crate, shard, data) {
+            //console.log(this.descShards);
+            this.descShards.get(crate)[shard].resolve(data.split("\n"));
+        },
+    };
+
     const staticFiles = path.join(doc_folder, "static.files");
     const searchJs = fs.readdirSync(staticFiles).find(f => f.match(/search.*\.js$/));
     const searchModule = require(path.join(staticFiles, searchJs));
@@ -474,7 +513,7 @@ function parseOptions(args) {
     return null;
 }
 
-function main(argv) {
+async function main(argv) {
     const opts = parseOptions(argv.slice(2));
     if (opts === null) {
         return 1;
@@ -482,7 +521,7 @@ function main(argv) {
 
     const parseAndSearch = loadSearchJS(
         opts["doc_folder"],
-        opts["resource_suffix"]
+        opts["resource_suffix"],
     );
     let errors = 0;
 
@@ -494,21 +533,29 @@ function main(argv) {
     };
 
     if (opts["test_file"].length !== 0) {
-        opts["test_file"].forEach(file => {
+        for (const file of opts["test_file"]) {
             process.stdout.write(`Testing ${file} ... `);
-            errors += runChecks(file, doSearch, parseAndSearch.parseQuery, getCorrections);
-        });
+            errors += await runChecks(file, doSearch, parseAndSearch.parseQuery, getCorrections);
+        }
     } else if (opts["test_folder"].length !== 0) {
-        fs.readdirSync(opts["test_folder"]).forEach(file => {
+        for (const file of fs.readdirSync(opts["test_folder"])) {
             if (!file.endsWith(".js")) {
-                return;
+                continue;
             }
             process.stdout.write(`Testing ${file} ... `);
-            errors += runChecks(path.join(opts["test_folder"], file), doSearch,
+            errors += await runChecks(path.join(opts["test_folder"], file), doSearch,
                     parseAndSearch.parseQuery, getCorrections);
-        });
+        }
     }
     return errors > 0 ? 1 : 0;
 }
 
-process.exit(main(process.argv));
+main(process.argv).catch(e => {
+    console.log(e);
+    process.exit(1);
+}).then(x => process.exit(x));
+
+process.on("beforeExit", () => {
+    console.log("process did not complete");
+    process.exit(1);
+});
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index bdee3afa6b7..347ea1223eb 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -31,7 +31,6 @@ run-make/compiler-rt-works-on-mingw/Makefile
 run-make/compressed-debuginfo/Makefile
 run-make/const-prop-lint/Makefile
 run-make/const_fn_mir/Makefile
-run-make/core-no-fp-fmt-parse/Makefile
 run-make/core-no-oom-handling/Makefile
 run-make/crate-data-smoke/Makefile
 run-make/crate-hash-rustc-version/Makefile
@@ -87,7 +86,6 @@ run-make/foreign-exceptions/Makefile
 run-make/foreign-rust-exceptions/Makefile
 run-make/fpic/Makefile
 run-make/glibc-staticlib-args/Makefile
-run-make/hir-tree/Makefile
 run-make/inaccessible-temp-dir/Makefile
 run-make/include_bytes_deps/Makefile
 run-make/incr-add-rust-src-component/Makefile
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index f6b1d45ee94..874c15ce41d 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -434,6 +434,7 @@
 "ui/closures/issue-111932.rs",
 "ui/closures/issue-113087.rs",
 "ui/closures/issue-11873.rs",
+"ui/closures/issue-1460.rs",
 "ui/closures/issue-23012-supertrait-signature-inference.rs",
 "ui/closures/issue-25439.rs",
 "ui/closures/issue-41366.rs",
@@ -1007,6 +1008,8 @@
 "ui/fmt/issue-86085.rs",
 "ui/fmt/issue-89173.rs",
 "ui/fmt/issue-91556.rs",
+"ui/fn/issue-1451.rs",
+"ui/fn/issue-1900.rs",
 "ui/fn/issue-3044.rs",
 "ui/fn/issue-3099.rs",
 "ui/fn/issue-3904.rs",
@@ -1129,7 +1132,6 @@
 "ui/generics/issue-98432.rs",
 "ui/higher-ranked/trait-bounds/issue-100689.rs",
 "ui/higher-ranked/trait-bounds/issue-102899.rs",
-"ui/higher-ranked/trait-bounds/issue-30786.rs",
 "ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs",
 "ui/higher-ranked/trait-bounds/issue-39292.rs",
 "ui/higher-ranked/trait-bounds/issue-42114.rs",
@@ -1550,7 +1552,6 @@
 "ui/issues/issue-13497-2.rs",
 "ui/issues/issue-13497.rs",
 "ui/issues/issue-13507-2.rs",
-"ui/issues/issue-1362.rs",
 "ui/issues/issue-13620.rs",
 "ui/issues/issue-13665.rs",
 "ui/issues/issue-13703.rs",
@@ -1576,12 +1577,8 @@
 "ui/issues/issue-14399.rs",
 "ui/issues/issue-14421.rs",
 "ui/issues/issue-14422.rs",
-"ui/issues/issue-1448-2.rs",
-"ui/issues/issue-1451.rs",
 "ui/issues/issue-14541.rs",
-"ui/issues/issue-1460.rs",
 "ui/issues/issue-14721.rs",
-"ui/issues/issue-1476.rs",
 "ui/issues/issue-14821.rs",
 "ui/issues/issue-14845.rs",
 "ui/issues/issue-14853.rs",
@@ -1631,7 +1628,6 @@
 "ui/issues/issue-16560.rs",
 "ui/issues/issue-16562.rs",
 "ui/issues/issue-16596.rs",
-"ui/issues/issue-1660.rs",
 "ui/issues/issue-16643.rs",
 "ui/issues/issue-16648.rs",
 "ui/issues/issue-16668.rs",
@@ -1645,7 +1641,6 @@
 "ui/issues/issue-16819.rs",
 "ui/issues/issue-16922-rpass.rs",
 "ui/issues/issue-16939.rs",
-"ui/issues/issue-1696.rs",
 "ui/issues/issue-16966.rs",
 "ui/issues/issue-16994.rs",
 "ui/issues/issue-17001.rs",
@@ -1725,7 +1720,6 @@
 "ui/issues/issue-18952.rs",
 "ui/issues/issue-18959.rs",
 "ui/issues/issue-18988.rs",
-"ui/issues/issue-1900.rs",
 "ui/issues/issue-19001.rs",
 "ui/issues/issue-19037.rs",
 "ui/issues/issue-19086.rs",
@@ -1753,12 +1747,10 @@
 "ui/issues/issue-19482.rs",
 "ui/issues/issue-19499.rs",
 "ui/issues/issue-19601.rs",
-"ui/issues/issue-1962.rs",
 "ui/issues/issue-19631.rs",
 "ui/issues/issue-19632.rs",
 "ui/issues/issue-19692.rs",
 "ui/issues/issue-19734.rs",
-"ui/issues/issue-1974.rs",
 "ui/issues/issue-19811-escape-unicode.rs",
 "ui/issues/issue-19850.rs",
 "ui/issues/issue-19922.rs",
@@ -2856,6 +2848,8 @@
 "ui/lint/unused/issue-92751.rs",
 "ui/lint/unused/issue-96606.rs",
 "ui/lint/use-redundant/issue-92904.rs",
+"ui/loops/issue-1962.rs",
+"ui/loops/issue-1974.rs",
 "ui/loops/issue-43162.rs",
 "ui/loops/issue-50576.rs",
 "ui/loops/issue-69225-SCEVAddExpr-wrap-flag.rs",
@@ -3045,6 +3039,8 @@
 "ui/mismatched_types/issue-118145-unwrap-for-shorthand.rs",
 "ui/mismatched_types/issue-118510.rs",
 "ui/mismatched_types/issue-13033.rs",
+"ui/mismatched_types/issue-1362.rs",
+"ui/mismatched_types/issue-1448-2.rs",
 "ui/mismatched_types/issue-19109.rs",
 "ui/mismatched_types/issue-26480.rs",
 "ui/mismatched_types/issue-35030.rs",
@@ -3860,6 +3856,7 @@
 "ui/stability-attribute/issue-28388-3.rs",
 "ui/stability-attribute/issue-99286-stable-intrinsics.rs",
 "ui/static/auxiliary/issue_24843.rs",
+"ui/static/issue-1660.rs",
 "ui/static/issue-18118-2.rs",
 "ui/static/issue-18118.rs",
 "ui/static/issue-24446.rs",
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index fe27964981e..454811c5fbb 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use std::path::{Path, PathBuf};
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: usize = 1750;
+const ISSUES_ENTRY_LIMIT: usize = 1733;
 const ROOT_ENTRY_LIMIT: usize = 860;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
diff --git a/tests/assembly/is_aligned.rs b/tests/assembly/is_aligned.rs
index 9d637793f87..14423a52064 100644
--- a/tests/assembly/is_aligned.rs
+++ b/tests/assembly/is_aligned.rs
@@ -7,7 +7,7 @@
 #![crate_type="rlib"]
 
 #![feature(core_intrinsics)]
-#![feature(pointer_is_aligned)]
+#![feature(pointer_is_aligned_to)]
 
 // CHECK-LABEL: is_aligned_to_unchecked
 // CHECK: decq
diff --git a/tests/assembly/x86_64-cmp.rs b/tests/assembly/x86_64-cmp.rs
new file mode 100644
index 00000000000..31efdda1bfa
--- /dev/null
+++ b/tests/assembly/x86_64-cmp.rs
@@ -0,0 +1,51 @@
+//@ revisions: DEBUG OPTIM
+//@ [DEBUG] compile-flags: -C opt-level=0
+//@ [OPTIM] compile-flags: -C opt-level=3
+//@ assembly-output: emit-asm
+//@ compile-flags: --crate-type=lib -C llvm-args=-x86-asm-syntax=intel
+//@ only-x86_64
+//@ ignore-sgx
+
+#![feature(core_intrinsics)]
+
+use std::intrinsics::three_way_compare;
+
+#[no_mangle]
+// CHECK-LABEL: signed_cmp:
+pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering {
+    // DEBUG: cmp
+    // DEBUG: setg
+    // DEBUG: and
+    // DEBUG: cmp
+    // DEBUG: setl
+    // DEBUG: and
+    // DEBUG: sub
+
+    // OPTIM: xor
+    // OPTIM: cmp
+    // OPTIM: setne
+    // OPTIM: mov
+    // OPTIM: cmovge
+    // OPTIM: ret
+    three_way_compare(a, b)
+}
+
+#[no_mangle]
+// CHECK-LABEL: unsigned_cmp:
+pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering {
+    // DEBUG: cmp
+    // DEBUG: seta
+    // DEBUG: and
+    // DEBUG: cmp
+    // DEBUG: setb
+    // DEBUG: and
+    // DEBUG: sub
+
+    // OPTIM: xor
+    // OPTIM: cmp
+    // OPTIM: setne
+    // OPTIM: mov
+    // OPTIM: cmovae
+    // OPTIM: ret
+    three_way_compare(a, b)
+}
diff --git a/tests/auxiliary/rust_test_helpers.c b/tests/auxiliary/rust_test_helpers.c
index 977ea487a98..965df44c676 100644
--- a/tests/auxiliary/rust_test_helpers.c
+++ b/tests/auxiliary/rust_test_helpers.c
@@ -118,6 +118,30 @@ rust_dbg_extern_identity_TwoDoubles(struct TwoDoubles u) {
     return u;
 }
 
+struct FiveU16s {
+    uint16_t one;
+    uint16_t two;
+    uint16_t three;
+    uint16_t four;
+    uint16_t five;
+};
+
+struct FiveU16s
+rust_dbg_extern_return_FiveU16s() {
+    struct FiveU16s s;
+    s.one = 10;
+    s.two = 20;
+    s.three = 30;
+    s.four = 40;
+    s.five = 50;
+    return s;
+}
+
+struct FiveU16s
+rust_dbg_extern_identity_FiveU16s(struct FiveU16s u) {
+    return u;
+}
+
 struct ManyInts {
     int8_t arg1;
     int16_t arg2;
diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs
new file mode 100644
index 00000000000..e6024f03425
--- /dev/null
+++ b/tests/codegen/cast-target-abi.rs
@@ -0,0 +1,280 @@
+// ignore-tidy-linelength
+//@ revisions:aarch64 loongarch64 powerpc64 sparc64
+//@ compile-flags: -O -C no-prepopulate-passes
+
+//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64] needs-llvm-components: arm
+//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
+//@[loongarch64] needs-llvm-components: loongarch
+//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
+//@[powerpc64] needs-llvm-components: powerpc
+//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
+//@[sparc64] needs-llvm-components: sparc
+
+// Tests that arguments with `PassMode::Cast` are handled correctly.
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang="sized"] trait Sized { }
+#[lang="freeze"] trait Freeze { }
+#[lang="copy"] trait Copy { }
+
+// This struct will be passed as a single `i64` or `i32`.
+// This may be (if `i64)) larger than the Rust layout, which is just `{ i16, i16 }`.
+#[repr(C)]
+pub struct TwoU16s {
+    a: u16,
+    b: u16,
+}
+
+// This struct will be passed as `[2 x i64]`.
+// This is larger than the Rust layout.
+#[repr(C)]
+pub struct FiveU16s {
+    a: u16,
+    b: u16,
+    c: u16,
+    d: u16,
+    e: u16,
+}
+
+// This struct will be passed as `[2 x double]`.
+// This is the same as the Rust layout.
+#[repr(C)]
+pub struct DoubleDouble {
+    f: f64,
+    g: f64,
+}
+
+// On loongarch, this struct will be passed as `{ double, float }`.
+// This is smaller than the Rust layout, which has trailing padding (`{ f64, f32, <f32 padding> }`)
+#[repr(C)]
+pub struct DoubleFloat {
+    f: f64,
+    g: f32,
+}
+
+extern "C" {
+    fn receives_twou16s(x: TwoU16s);
+    fn returns_twou16s() -> TwoU16s;
+
+    fn receives_fiveu16s(x: FiveU16s);
+    fn returns_fiveu16s() -> FiveU16s;
+
+    fn receives_doubledouble(x: DoubleDouble);
+    fn returns_doubledouble() -> DoubleDouble;
+
+    // These functions cause an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+    #[cfg(not(target_arch = "sparc64"))]
+    fn receives_doublefloat(x: DoubleFloat);
+    #[cfg(not(target_arch = "sparc64"))]
+    fn returns_doublefloat() -> DoubleFloat;
+}
+
+// CHECK-LABEL: @call_twou16s
+#[no_mangle]
+pub unsafe fn call_twou16s() {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i32]], align [[ABI_ALIGN:4]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 4, i1 false)
+    // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // CHECK: call void @receives_twou16s([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = TwoU16s { a: 1, b: 2 };
+    receives_twou16s(x);
+}
+
+// CHECK-LABEL: @return_twou16s
+#[no_mangle]
+pub unsafe fn return_twou16s() -> TwoU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca %TwoU16s, align 2
+    // powerpc64: call void @returns_twou16s(ptr {{.+}} [[RETVAL]])
+
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+    // sparc64:     [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    returns_twou16s()
+}
+
+// CHECK-LABEL: @call_fiveu16s
+#[no_mangle]
+pub unsafe fn call_fiveu16s() {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca %FiveU16s, align 2
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 10, i1 false)
+    // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // CHECK: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = FiveU16s { a: 1, b: 2, c: 3, d: 4, e: 5 };
+    receives_fiveu16s(x);
+}
+
+// CHECK-LABEL: @return_fiveu16s
+// CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] dereferenceable(10) [[RET_PTR:%.+]])
+#[no_mangle]
+pub unsafe fn return_fiveu16s() -> FiveU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: call void @returns_fiveu16s(ptr {{.+}} [[RET_PTR]])
+
+
+    // The other targets copy the cast ABI type to the sret pointer.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    returns_fiveu16s()
+}
+
+// CHECK-LABEL: @call_doubledouble
+#[no_mangle]
+pub unsafe fn call_doubledouble() {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x double\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+    // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // CHECK: call void @receives_doubledouble([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = DoubleDouble { f: 1., g: 2. };
+    receives_doubledouble(x);
+}
+
+// CHECK-LABEL: @return_doubledouble
+#[no_mangle]
+pub unsafe fn return_doubledouble() -> DoubleDouble {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca %DoubleDouble, align 8
+    // powerpc64: call void @returns_doubledouble(ptr {{.+}} [[RETVAL]])
+
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x double\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+    // sparc64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    returns_doubledouble()
+}
+
+// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @call_doublefloat
+// loongarch64-LABEL: @call_doublefloat
+// powerpc64-LABEL:   @call_doublefloat
+#[no_mangle]
+pub unsafe fn call_doublefloat() {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float }]], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+    // powerpc64:   [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false)
+    // powerpc64:   call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    // loongarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    // powerpc64:   call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    let x = DoubleFloat { f: 1., g: 2. };
+    receives_doublefloat(x);
+}
+
+// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @return_doublefloat
+// loongarch64-LABEL: @return_doublefloat
+// powerpc64-LABEL:   @return_doublefloat
+#[no_mangle]
+pub unsafe fn return_doublefloat() -> DoubleFloat {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca %DoubleFloat, align 8
+    // powerpc64: call void @returns_doublefloat(ptr {{.+}} [[RETVAL]])
+
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float }]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doublefloat()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doublefloat()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    returns_doublefloat()
+}
diff --git a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
index 7eda6cf4d57..8b32e902b3f 100644
--- a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
+++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
@@ -1,8 +1,21 @@
+//@ revisions: linux apple
+//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes
+
+//@[linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[linux] needs-llvm-components: x86
+//@[apple] compile-flags: --target x86_64-apple-darwin
+//@[apple] needs-llvm-components: x86
+
 // Regression test for #29988
 
-//@ compile-flags: -C no-prepopulate-passes
-//@ only-x86_64
-//@ ignore-windows
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang="sized"] trait Sized { }
+#[lang="freeze"] trait Freeze { }
+#[lang="copy"] trait Copy { }
 
 #[repr(C)]
 struct S {
@@ -15,11 +28,14 @@ extern "C" {
     fn foo(s: S);
 }
 
-fn main() {
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test() {
     let s = S { f1: 1, f2: 2, f3: 3 };
     unsafe {
-        // CHECK: load { i64, i32 }, {{.*}}, align 4
-        // CHECK: call void @foo({ i64, i32 } {{.*}})
+        // CHECK: [[ALLOCA:%.+]] = alloca { i64, i32 }, align 8
+        // CHECK: [[LOAD:%.+]] = load { i64, i32 }, ptr [[ALLOCA]], align 8
+        // CHECK: call void @foo({ i64, i32 } [[LOAD]])
         foo(s);
     }
 }
diff --git a/tests/codegen/enum/uninhabited_enum_default_branch.rs b/tests/codegen/enum/uninhabited_enum_default_branch.rs
deleted file mode 100644
index 5f318f18dec..00000000000
--- a/tests/codegen/enum/uninhabited_enum_default_branch.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-//@ compile-flags: -O
-
-#![crate_type = "lib"]
-
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Int(u32);
-
-const A: Int = Int(201);
-const B: Int = Int(270);
-const C: Int = Int(153);
-
-// CHECK-LABEL: @foo(
-// CHECK-SAME: [[TMP0:%.*]])
-// CHECK-NEXT:  start:
-// CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[TMP0]], -201
-// CHECK-NEXT:    icmp ult i32 [[TMP1]], 70
-// CHECK-NEXT:    icmp eq i32 [[TMP0]], 153
-// CHECK-NEXT:    [[SPEC_SELECT:%.*]] = or i1
-// CHECK-NEXT:    ret i1 [[SPEC_SELECT]]
-#[no_mangle]
-pub fn foo(x: Int) -> bool {
-    (x >= A && x <= B)
-        || x == C
-}
diff --git a/tests/codegen/enum/unreachable_enum_default_branch.rs b/tests/codegen/enum/unreachable_enum_default_branch.rs
new file mode 100644
index 00000000000..dae01cfb055
--- /dev/null
+++ b/tests/codegen/enum/unreachable_enum_default_branch.rs
@@ -0,0 +1,43 @@
+//@ compile-flags: -O
+
+#![crate_type = "lib"]
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Int(u32);
+
+const A: Int = Int(201);
+const B: Int = Int(270);
+const C: Int = Int(153);
+
+// The code is from https://github.com/rust-lang/rust/issues/119520.
+// This code will basically turn into `matches!(x.partial_cmp(&A), Some(Greater | Equal))`.
+// The otherwise branch must be `Less`.
+// CHECK-LABEL: @implicit_match(
+// CHECK-SAME: [[TMP0:%.*]])
+// CHECK-NEXT:  start:
+// CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[TMP0]], -201
+// CHECK-NEXT:    icmp ult i32 [[TMP1]], 70
+// CHECK-NEXT:    icmp eq i32 [[TMP0]], 153
+// CHECK-NEXT:    [[SPEC_SELECT:%.*]] = or i1
+// CHECK-NEXT:    ret i1 [[SPEC_SELECT]]
+#[no_mangle]
+pub fn implicit_match(x: Int) -> bool {
+    (x >= A && x <= B)
+        || x == C
+}
+
+// The code is from https://github.com/rust-lang/rust/issues/110097.
+// We expect it to generate the same optimized code as a full match.
+// CHECK-LABEL: @if_let(
+// CHECK-NEXT:  start:
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: ret
+#[no_mangle]
+pub fn if_let(val: Result<i32, ()>) -> Result<i32, ()> {
+    if let Ok(x) = val {
+        Ok(x)
+    } else {
+        Err(())
+    }
+}
diff --git a/tests/codegen/intrinsics/three_way_compare.rs b/tests/codegen/intrinsics/three_way_compare.rs
new file mode 100644
index 00000000000..f3b631abc22
--- /dev/null
+++ b/tests/codegen/intrinsics/three_way_compare.rs
@@ -0,0 +1,47 @@
+//@ revisions: DEBUG OPTIM
+//@ [DEBUG] compile-flags: -C opt-level=0
+//@ [OPTIM] compile-flags: -C opt-level=3
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::three_way_compare;
+
+#[no_mangle]
+// CHECK-LABEL: @signed_cmp
+// DEBUG-SAME: (i16 %a, i16 %b)
+// OPTIM-SAME: (i16 noundef %a, i16 noundef %b)
+pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering {
+    // DEBUG: %[[GT:.+]] = icmp sgt i16 %a, %b
+    // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8
+    // DEBUG: %[[LT:.+]] = icmp slt i16 %a, %b
+    // DEBUG: %[[ZLT:.+]] = zext i1 %[[LT]] to i8
+    // DEBUG: %[[R:.+]] = sub nsw i8 %[[ZGT]], %[[ZLT]]
+
+    // OPTIM: %[[LT:.+]] = icmp slt i16 %a, %b
+    // OPTIM: %[[NE:.+]] = icmp ne i16 %a, %b
+    // OPTIM: %[[CGE:.+]] = select i1 %[[NE]], i8 1, i8 0
+    // OPTIM: %[[CGEL:.+]] = select i1 %[[LT]], i8 -1, i8 %[[CGE]]
+    // OPTIM: ret i8 %[[CGEL]]
+    three_way_compare(a, b)
+}
+
+#[no_mangle]
+// CHECK-LABEL: @unsigned_cmp
+// DEBUG-SAME: (i16 %a, i16 %b)
+// OPTIM-SAME: (i16 noundef %a, i16 noundef %b)
+pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering {
+    // DEBUG: %[[GT:.+]] = icmp ugt i16 %a, %b
+    // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8
+    // DEBUG: %[[LT:.+]] = icmp ult i16 %a, %b
+    // DEBUG: %[[ZLT:.+]] = zext i1 %[[LT]] to i8
+    // DEBUG: %[[R:.+]] = sub nsw i8 %[[ZGT]], %[[ZLT]]
+
+    // OPTIM: %[[LT:.+]] = icmp ult i16 %a, %b
+    // OPTIM: %[[NE:.+]] = icmp ne i16 %a, %b
+    // OPTIM: %[[CGE:.+]] = select i1 %[[NE]], i8 1, i8 0
+    // OPTIM: %[[CGEL:.+]] = select i1 %[[LT]], i8 -1, i8 %[[CGE]]
+    // OPTIM: ret i8 %[[CGEL]]
+    three_way_compare(a, b)
+}
diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
index 671db563dde..999fd292fe7 100644
--- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
+++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
@@ -18,5 +18,5 @@ impl Trait1 for Type1 {
 }
 
 
-// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"}
-// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"}
diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs
index 9cf2f2b0cb6..7d020fbb4d2 100644
--- a/tests/codegen/unchecked_shifts.rs
+++ b/tests/codegen/unchecked_shifts.rs
@@ -2,6 +2,7 @@
 
 #![crate_type = "lib"]
 #![feature(unchecked_shifts)]
+#![feature(core_intrinsics)]
 
 // CHECK-LABEL: @unchecked_shl_unsigned_same
 #[no_mangle]
@@ -19,7 +20,7 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 {
     // This uses -DAG to avoid failing on irrelevant reorderings,
     // like emitting the truncation earlier.
 
-    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 65536
+    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16
     // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
     // CHECK-DAG: %[[TRUNC:.+]] = trunc i32 %b to i16
     // CHECK-DAG: shl i16 %a, %[[TRUNC]]
@@ -51,7 +52,7 @@ pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 {
     // This uses -DAG to avoid failing on irrelevant reorderings,
     // like emitting the truncation earlier.
 
-    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 32768
+    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16
     // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
     // CHECK-DAG: %[[TRUNC:.+]] = trunc i32 %b to i16
     // CHECK-DAG: ashr i16 %a, %[[TRUNC]]
@@ -66,3 +67,47 @@ pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 {
     // CHECK: ashr i64 %a, %[[EXT]]
     a.unchecked_shr(b)
 }
+
+// CHECK-LABEL: @unchecked_shr_u128_i8
+#[no_mangle]
+pub unsafe fn unchecked_shr_u128_i8(a: u128, b: i8) -> u128 {
+    // CHECK-NOT: assume
+    // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i8 %b to i128
+    // CHECK: lshr i128 %a, %[[EXT]]
+    std::intrinsics::unchecked_shr(a, b)
+}
+
+// CHECK-LABEL: @unchecked_shl_i128_u8
+#[no_mangle]
+pub unsafe fn unchecked_shl_i128_u8(a: i128, b: u8) -> i128 {
+    // CHECK-NOT: assume
+    // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i8 %b to i128
+    // CHECK: shl i128 %a, %[[EXT]]
+    std::intrinsics::unchecked_shl(a, b)
+}
+
+// CHECK-LABEL: @unchecked_shl_u8_i128
+#[no_mangle]
+pub unsafe fn unchecked_shl_u8_i128(a: u8, b: i128) -> u8 {
+    // This uses -DAG to avoid failing on irrelevant reorderings,
+    // like emitting the truncation earlier.
+
+    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8
+    // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
+    // CHECK-DAG: %[[TRUNC:.+]] = trunc i128 %b to i8
+    // CHECK-DAG: shl i8 %a, %[[TRUNC]]
+    std::intrinsics::unchecked_shl(a, b)
+}
+
+// CHECK-LABEL: @unchecked_shr_i8_u128
+#[no_mangle]
+pub unsafe fn unchecked_shr_i8_u128(a: i8, b: u128) -> i8 {
+    // This uses -DAG to avoid failing on irrelevant reorderings,
+    // like emitting the truncation earlier.
+
+    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8
+    // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
+    // CHECK-DAG: %[[TRUNC:.+]] = trunc i128 %b to i8
+    // CHECK-DAG: ashr i8 %a, %[[TRUNC]]
+    std::intrinsics::unchecked_shr(a, b)
+}
diff --git a/tests/codegen/vec_pop_push_noop.rs b/tests/codegen/vec_pop_push_noop.rs
index 83765d10854..4d76c24a9d9 100644
--- a/tests/codegen/vec_pop_push_noop.rs
+++ b/tests/codegen/vec_pop_push_noop.rs
@@ -5,10 +5,10 @@
 #[no_mangle]
 // CHECK-LABEL: @noop(
 pub fn noop(v: &mut Vec<u8>) {
-    // CHECK-NOT: reserve_for_push
+    // CHECK-NOT: grow_one
     // CHECK-NOT: call
     // CHECK: tail call void @llvm.assume
-    // CHECK-NOT: reserve_for_push
+    // CHECK-NOT: grow_one
     // CHECK-NOT: call
     // CHECK: ret
     if let Some(x) = v.pop() {
@@ -19,6 +19,6 @@ pub fn noop(v: &mut Vec<u8>) {
 #[no_mangle]
 // CHECK-LABEL: @push_byte(
 pub fn push_byte(v: &mut Vec<u8>) {
-    // CHECK: call {{.*}}reserve_for_push
+    // CHECK: call {{.*}}grow_one
     v.push(3);
 }
diff --git a/tests/debuginfo/path.rs b/tests/debuginfo/path.rs
new file mode 100644
index 00000000000..42bbacc3a91
--- /dev/null
+++ b/tests/debuginfo/path.rs
@@ -0,0 +1,29 @@
+//@ ignore-gdb
+
+//@ compile-flags:-g
+
+// === LLDB TESTS =================================================================================
+
+// lldb-command:run
+
+// lldb-command:print pathbuf
+// lldb-check:[...] "/some/path" { inner = "/some/path" { inner = { inner = size=10 { [0] = '/' [1] = 's' [2] = 'o' [3] = 'm' [4] = 'e' [5] = '/' [6] = 'p' [7] = 'a' [8] = 't' [9] = 'h' } } } }
+// lldb-command:po pathbuf
+// lldb-check:"/some/path"
+// lldb-command:print path
+// lldb-check:[...] "/some/path" { data_ptr = [...] length = 10 }
+// lldb-command:po path
+// lldb-check:"/some/path"
+
+use std::path::Path;
+
+fn main() {
+    let path = Path::new("/some/path");
+    let pathbuf = path.to_path_buf();
+
+    zzz(); // #break
+}
+
+fn zzz() {
+    ()
+}
diff --git a/tests/incremental/hashes/function_interfaces.rs b/tests/incremental/hashes/function_interfaces.rs
index 3be30fab99c..ab4d578458d 100644
--- a/tests/incremental/hashes/function_interfaces.rs
+++ b/tests/incremental/hashes/function_interfaces.rs
@@ -104,17 +104,17 @@ pub fn order_of_parameters(p2: i64, p1: i32) {}
 // Unsafe ----------------------------------------------------------------------
 
 #[cfg(any(cfail1,cfail4))]
-pub fn make_unsafe() {}
+pub        fn make_unsafe() {}
 
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(
     cfg = "cfail2",
-    except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig"
+    except = "opt_hir_owner_nodes, typeck, fn_sig"
 )]
 #[rustc_clean(cfg = "cfail3")]
 #[rustc_clean(
     cfg = "cfail5",
-    except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig"
+    except = "opt_hir_owner_nodes, typeck, fn_sig"
 )]
 #[rustc_clean(cfg = "cfail6")]
 pub unsafe fn make_unsafe() {}
@@ -217,7 +217,7 @@ pub fn second_trait_bound<T: Eq + Clone>() {}
 pub fn second_builtin_bound<T: Send        >() {}
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, predicates_of")]
+#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes")]
 #[rustc_clean(cfg = "cfail3")]
 #[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, predicates_of")]
 #[rustc_clean(cfg = "cfail6")]
diff --git a/tests/incremental/hashes/inherent_impls.rs b/tests/incremental/hashes/inherent_impls.rs
index 2b0de1edc0c..caea394977a 100644
--- a/tests/incremental/hashes/inherent_impls.rs
+++ b/tests/incremental/hashes/inherent_impls.rs
@@ -348,9 +348,9 @@ impl Foo {
 // Make method unsafe ----------------------------------------------------------
 #[cfg(any(cfail1,cfail4))]
 impl Foo {
-    //------------------------------------------------------------------------------------
+    //----------------------------------------------------------------------
     //--------------------------
-    //------------------------------------------------------------------------------------
+    //----------------------------------------------------------------------
     //--------------------------
     pub        fn make_method_unsafe(&self) { }
 }
@@ -361,9 +361,9 @@ impl Foo {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
-    #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")]
+    #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,typeck")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")]
+    #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,typeck")]
     #[rustc_clean(cfg="cfail6")]
     pub unsafe fn make_method_unsafe(&self) { }
 }
diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
index 3b7c4b8796e..ef51b07827f 100644
--- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
+++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
@@ -17,8 +17,6 @@ fn main() -> () {
             let _3: *mut usize;
             scope 3 {
                 debug z => _3;
-                scope 4 {
-                }
             }
         }
     }
diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
index 3dcddea0353..d1aa9382a2c 100644
--- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
+++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
@@ -17,8 +17,6 @@ fn main() -> () {
             let _3: *mut usize;
             scope 3 {
                 debug z => _3;
-                scope 4 {
-                }
             }
         }
     }
diff --git a/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir b/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir
index 6c3128f8c36..005b3ee3b24 100644
--- a/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir
+++ b/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir
@@ -3,8 +3,6 @@
 fn main() -> () {
     let mut _0: ();
     let _1: ();
-    scope 1 {
-    }
 
     bb0: {
         StorageLive(_1);
diff --git a/tests/mir-opt/box_expr.main.ElaborateDrops.diff b/tests/mir-opt/box_expr.main.ElaborateDrops.diff
index 88b12f19e64..ec40fac2894 100644
--- a/tests/mir-opt/box_expr.main.ElaborateDrops.diff
+++ b/tests/mir-opt/box_expr.main.ElaborateDrops.diff
@@ -15,8 +15,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
index d697ea49231..d2a0fb0cb3c 100644
--- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
+++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
@@ -93,17 +93,13 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
         debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()});
         let _17: ();
         scope 2 {
-        }
-        scope 3 {
             debug result => _17;
         }
     }
-    scope 4 {
+    scope 3 {
         debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()});
         let _33: ();
-        scope 5 {
-        }
-        scope 6 {
+        scope 4 {
             debug result => _33;
         }
     }
diff --git a/tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir b/tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir
index 0dc46d61eff..faff79e8c57 100644
--- a/tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir
+++ b/tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir
@@ -4,7 +4,7 @@ fn int_to_ptr(_1: usize) -> *const i32 {
     let mut _0: *const i32;
 
     bb0: {
-        _0 = _1 as *const i32 (PointerFromExposedAddress);
+        _0 = _1 as *const i32 (PointerWithExposedProvenance);
         return;
     }
 }
diff --git a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir b/tests/mir-opt/building/match/deref-patterns/string.foo.PreCodegen.after.mir
index 1e4f7485089..1e4f7485089 100644
--- a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir
+++ b/tests/mir-opt/building/match/deref-patterns/string.foo.PreCodegen.after.mir
diff --git a/tests/mir-opt/deref-patterns/string.rs b/tests/mir-opt/building/match/deref-patterns/string.rs
index bb4b5379b27..bb4b5379b27 100644
--- a/tests/mir-opt/deref-patterns/string.rs
+++ b/tests/mir-opt/building/match/deref-patterns/string.rs
diff --git a/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
index 596dcef85fd..596dcef85fd 100644
--- a/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
diff --git a/tests/mir-opt/exponential_or.rs b/tests/mir-opt/building/match/exponential_or.rs
index 89963b9bdf4..89963b9bdf4 100644
--- a/tests/mir-opt/exponential_or.rs
+++ b/tests/mir-opt/building/match/exponential_or.rs
diff --git a/tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir
index 194afdf7dd8..194afdf7dd8 100644
--- a/tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir
+++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir
diff --git a/tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir
index ae83075434f..ae83075434f 100644
--- a/tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir
+++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir
diff --git a/tests/mir-opt/building/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir
index b71b2412cdf..dfa31cfff6b 100644
--- a/tests/mir-opt/building/match_false_edges.main.built.after.mir
+++ b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir
@@ -48,7 +48,7 @@ fn main() -> () {
     }
 
     bb2: {
-        falseEdge -> [real: bb15, imaginary: bb6];
+        falseEdge -> [real: bb15, imaginary: bb3];
     }
 
     bb3: {
diff --git a/tests/mir-opt/building/match_false_edges.rs b/tests/mir-opt/building/match/match_false_edges.rs
index 839eda40c85..839eda40c85 100644
--- a/tests/mir-opt/building/match_false_edges.rs
+++ b/tests/mir-opt/building/match/match_false_edges.rs
diff --git a/tests/mir-opt/building/simple_match.match_bool.built.after.mir b/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir
index faa2456fd10..faa2456fd10 100644
--- a/tests/mir-opt/building/simple_match.match_bool.built.after.mir
+++ b/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir
diff --git a/tests/mir-opt/building/simple_match.rs b/tests/mir-opt/building/match/simple_match.rs
index 4f0a3046a06..4f0a3046a06 100644
--- a/tests/mir-opt/building/simple_match.rs
+++ b/tests/mir-opt/building/match/simple_match.rs
diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
new file mode 100644
index 00000000000..c3497c6989d
--- /dev/null
+++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
@@ -0,0 +1,118 @@
+// MIR for `constant_eq` after SimplifyCfg-initial
+
+fn constant_eq(_1: &str, _2: bool) -> u32 {
+    debug s => _1;
+    debug b => _2;
+    let mut _0: u32;
+    let mut _3: (&str, bool);
+    let mut _4: &str;
+    let mut _5: bool;
+    let mut _6: bool;
+    let mut _7: bool;
+    let mut _8: &&str;
+    let mut _9: &bool;
+    let mut _10: bool;
+
+    bb0: {
+        StorageLive(_3);
+        StorageLive(_4);
+        _4 = _1;
+        StorageLive(_5);
+        _5 = _2;
+        _3 = (move _4, move _5);
+        StorageDead(_5);
+        StorageDead(_4);
+        PlaceMention(_3);
+        _7 = <str as PartialEq>::eq((_3.0: &str), const "a") -> [return: bb11, unwind: bb19];
+    }
+
+    bb1: {
+        switchInt((_3.1: bool)) -> [0: bb2, otherwise: bb3];
+    }
+
+    bb2: {
+        _0 = const 5_u32;
+        goto -> bb18;
+    }
+
+    bb3: {
+        falseEdge -> [real: bb17, imaginary: bb2];
+    }
+
+    bb4: {
+        falseEdge -> [real: bb12, imaginary: bb7];
+    }
+
+    bb5: {
+        switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb6];
+    }
+
+    bb6: {
+        falseEdge -> [real: bb16, imaginary: bb1];
+    }
+
+    bb7: {
+        _6 = <str as PartialEq>::eq((_3.0: &str), const "b") -> [return: bb10, unwind: bb19];
+    }
+
+    bb8: {
+        switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb9];
+    }
+
+    bb9: {
+        falseEdge -> [real: bb15, imaginary: bb5];
+    }
+
+    bb10: {
+        switchInt(move _6) -> [0: bb1, otherwise: bb8];
+    }
+
+    bb11: {
+        switchInt(move _7) -> [0: bb7, otherwise: bb4];
+    }
+
+    bb12: {
+        _8 = &fake (_3.0: &str);
+        _9 = &fake (_3.1: bool);
+        StorageLive(_10);
+        _10 = const true;
+        switchInt(move _10) -> [0: bb14, otherwise: bb13];
+    }
+
+    bb13: {
+        StorageDead(_10);
+        FakeRead(ForMatchGuard, _8);
+        FakeRead(ForMatchGuard, _9);
+        _0 = const 1_u32;
+        goto -> bb18;
+    }
+
+    bb14: {
+        StorageDead(_10);
+        falseEdge -> [real: bb5, imaginary: bb7];
+    }
+
+    bb15: {
+        _0 = const 2_u32;
+        goto -> bb18;
+    }
+
+    bb16: {
+        _0 = const 3_u32;
+        goto -> bb18;
+    }
+
+    bb17: {
+        _0 = const 4_u32;
+        goto -> bb18;
+    }
+
+    bb18: {
+        StorageDead(_3);
+        return;
+    }
+
+    bb19 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir
new file mode 100644
index 00000000000..4a1e4fb9ec5
--- /dev/null
+++ b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir
@@ -0,0 +1,88 @@
+// MIR for `disjoint_ranges` after SimplifyCfg-initial
+
+fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
+    debug x => _1;
+    debug b => _2;
+    let mut _0: u32;
+    let mut _3: bool;
+    let mut _4: bool;
+    let mut _5: bool;
+    let mut _6: bool;
+    let mut _7: &i32;
+    let mut _8: bool;
+
+    bb0: {
+        PlaceMention(_1);
+        _5 = Le(const 0_i32, _1);
+        switchInt(move _5) -> [0: bb3, otherwise: bb8];
+    }
+
+    bb1: {
+        _0 = const 3_u32;
+        goto -> bb14;
+    }
+
+    bb2: {
+        falseEdge -> [real: bb9, imaginary: bb3];
+    }
+
+    bb3: {
+        _3 = Le(const 10_i32, _1);
+        switchInt(move _3) -> [0: bb5, otherwise: bb7];
+    }
+
+    bb4: {
+        falseEdge -> [real: bb12, imaginary: bb5];
+    }
+
+    bb5: {
+        switchInt(_1) -> [4294967295: bb6, otherwise: bb1];
+    }
+
+    bb6: {
+        falseEdge -> [real: bb13, imaginary: bb1];
+    }
+
+    bb7: {
+        _4 = Le(_1, const 20_i32);
+        switchInt(move _4) -> [0: bb5, otherwise: bb4];
+    }
+
+    bb8: {
+        _6 = Lt(_1, const 10_i32);
+        switchInt(move _6) -> [0: bb3, otherwise: bb2];
+    }
+
+    bb9: {
+        _7 = &fake _1;
+        StorageLive(_8);
+        _8 = _2;
+        switchInt(move _8) -> [0: bb11, otherwise: bb10];
+    }
+
+    bb10: {
+        StorageDead(_8);
+        FakeRead(ForMatchGuard, _7);
+        _0 = const 0_u32;
+        goto -> bb14;
+    }
+
+    bb11: {
+        StorageDead(_8);
+        falseEdge -> [real: bb1, imaginary: bb3];
+    }
+
+    bb12: {
+        _0 = const 1_u32;
+        goto -> bb14;
+    }
+
+    bb13: {
+        _0 = const 2_u32;
+        goto -> bb14;
+    }
+
+    bb14: {
+        return;
+    }
+}
diff --git a/tests/mir-opt/building/match/sort_candidates.rs b/tests/mir-opt/building/match/sort_candidates.rs
new file mode 100644
index 00000000000..a2583ff8284
--- /dev/null
+++ b/tests/mir-opt/building/match/sort_candidates.rs
@@ -0,0 +1,41 @@
+// Check specific cases of sorting candidates in match lowering.
+#![feature(exclusive_range_pattern)]
+
+// EMIT_MIR sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
+fn constant_eq(s: &str, b: bool) -> u32 {
+    // Check that we only test "a" once
+
+    // CHECK-LABEL: fn constant_eq(
+    // CHECK: bb0: {
+    // CHECK: [[a:_.*]] = const "a";
+    // CHECK-NOT: {{_.*}} = const "a";
+    match (s, b) {
+        ("a", _) if true => 1,
+        ("b", true) => 2,
+        ("a", true) => 3,
+        (_, true) => 4,
+        _ => 5,
+    }
+}
+
+// EMIT_MIR sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir
+fn disjoint_ranges(x: i32, b: bool) -> u32 {
+    // When `(0..=10).contains(x) && !b`, we should jump to the last arm without testing the two
+    // other candidates.
+
+    // CHECK-LABEL: fn disjoint_ranges(
+    // CHECK: debug b => _2;
+    // CHECK: bb0: {
+    // CHECK: switchInt(_2) -> [0: [[jump:bb.*]], otherwise: {{bb.*}}];
+    // CHECK: [[jump]]: {
+    // CHECK-NEXT: _0 = const 3_u32;
+    // CHECK-NEXT: return;
+    match x {
+        0..10 if b => 0,
+        10..=20 => 1,
+        -1 => 2,
+        _ => 3,
+    }
+}
+
+fn main() {}
diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
index 128af9c5602..db758368a13 100644
--- a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
+++ b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
@@ -16,14 +16,10 @@ fn move_out_by_subslice() -> () {
     scope 1 {
         debug a => _1;
         let _12: [std::boxed::Box<i32>; 2];
-        scope 4 {
+        scope 2 {
             debug _y => _12;
         }
     }
-    scope 2 {
-    }
-    scope 3 {
-    }
 
     bb0: {
         StorageLive(_1);
diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
index d50a6872a41..84cd557715c 100644
--- a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
+++ b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
@@ -16,14 +16,10 @@ fn move_out_from_end() -> () {
     scope 1 {
         debug a => _1;
         let _12: std::boxed::Box<i32>;
-        scope 4 {
+        scope 2 {
             debug _y => _12;
         }
     }
-    scope 2 {
-    }
-    scope 3 {
-    }
 
     bb0: {
         StorageLive(_1);
diff --git a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
index 3596671f614..bfefd2b8c95 100644
--- a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
+++ b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
@@ -9,8 +9,6 @@
       let mut _4: &i32;
       let _5: *const i32;
 +     let mut _6: &[&i32; 1];
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff
index a044cfc62e2..3f4958f60e8 100644
--- a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff
+++ b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff
@@ -14,8 +14,6 @@
               debug ptr => _3;
               let _5: bool;
               scope 3 {
-              }
-              scope 4 {
                   debug ret => _5;
               }
           }
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
index 20fda589c39..826f4c34277 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
@@ -13,11 +13,9 @@
       let mut _9: &[i32; 3];
       scope 1 {
           debug a => _1;
+          let _5: i32;
           scope 2 {
-              let _5: i32;
-              scope 3 {
-                  debug _b => _5;
-              }
+              debug _b => _5;
           }
       }
   
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
index f1b90c28e72..0e2ec65652f 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
@@ -13,11 +13,9 @@
       let mut _9: &[i32; 3];
       scope 1 {
           debug a => _1;
+          let _5: i32;
           scope 2 {
-              let _5: i32;
-              scope 3 {
-                  debug _b => _5;
-              }
+              debug _b => _5;
           }
       }
   
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
index 20fda589c39..826f4c34277 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
@@ -13,11 +13,9 @@
       let mut _9: &[i32; 3];
       scope 1 {
           debug a => _1;
+          let _5: i32;
           scope 2 {
-              let _5: i32;
-              scope 3 {
-                  debug _b => _5;
-              }
+              debug _b => _5;
           }
       }
   
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
index f1b90c28e72..0e2ec65652f 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
@@ -13,11 +13,9 @@
       let mut _9: &[i32; 3];
       scope 1 {
           debug a => _1;
+          let _5: i32;
           scope 2 {
-              let _5: i32;
-              scope 3 {
-                  debug _b => _5;
-              }
+              debug _b => _5;
           }
       }
   
diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
index 59ee38f5a2b..a408c197fd1 100644
--- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
@@ -15,8 +15,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
index 9d87bd809d1..5706a739602 100644
--- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
@@ -15,8 +15,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff b/tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff
index b389080c497..99a6ba7d08a 100644
--- a/tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff
+++ b/tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff
@@ -11,8 +11,6 @@
           debug v => _1;
           let _4: bool;
           scope 2 {
-          }
-          scope 3 {
               debug y => _4;
           }
       }
diff --git a/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff b/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff
index da5bf1cf42c..f5041365604 100644
--- a/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff
+++ b/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff
@@ -12,24 +12,18 @@
       scope 1 {
           debug _invalid_char => _1;
           let _3: [E; 1];
-          scope 3 {
+          scope 2 {
               debug _invalid_tag => _3;
               let _6: [Empty; 1];
-              scope 5 {
+              scope 3 {
                   debug _enum_without_variants => const [ZeroSized: Empty];
                   let _9: main::Str<"���">;
-                  scope 7 {
+                  scope 4 {
                       debug _non_utf8_str => const Str::<"���">;
                   }
               }
-              scope 6 {
-              }
-          }
-          scope 4 {
           }
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff
index 455c2375eff..6e5ad8d6b81 100644
--- a/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff
+++ b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff
@@ -12,26 +12,20 @@
       scope 1 {
           debug _invalid_char => _1;
           let _3: [E; 1];
-          scope 3 {
+          scope 2 {
               debug _invalid_tag => _3;
               let _6: [Empty; 1];
-              scope 5 {
+              scope 3 {
 -                 debug _enum_without_variants => _6;
 +                 debug _enum_without_variants => const [ZeroSized: Empty];
                   let _9: main::Str<"���">;
-                  scope 7 {
+                  scope 4 {
 -                     debug _non_utf8_str => _9;
 +                     debug _non_utf8_str => const Str::<"���">;
                   }
               }
-              scope 6 {
-              }
-          }
-          scope 4 {
           }
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff
index e113f43a56e..31c839f6749 100644
--- a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff
@@ -11,8 +11,6 @@
           debug x => _1;
           let _5: u32;
           scope 2 {
-          }
-          scope 3 {
               debug y => _5;
           }
       }
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff
index 596eb1a9966..79a95b618d1 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const main::FOO;
           _2 = &raw const (*_3);
-          _1 = move _2 as usize (PointerExposeAddress);
+          _1 = move _2 as usize (PointerExposeProvenance);
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_4);
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff
index 995f281ecf5..9d1bcd92fef 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const main::FOO;
           _2 = &raw const (*_3);
-          _1 = move _2 as usize (PointerExposeAddress);
+          _1 = move _2 as usize (PointerExposeProvenance);
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_4);
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.rs b/tests/mir-opt/const_prop/pointer_expose_provenance.rs
index a6b4f8857c3..840a4d65f3d 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.rs
+++ b/tests/mir-opt/const_prop/pointer_expose_provenance.rs
@@ -4,12 +4,12 @@
 #[inline(never)]
 fn read(_: usize) { }
 
-// EMIT_MIR pointer_expose_address.main.GVN.diff
+// EMIT_MIR pointer_expose_provenance.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: [[ptr:_.*]] = const main::FOO;
     // CHECK: [[ref:_.*]] = &raw const (*[[ptr]]);
-    // CHECK: [[x:_.*]] = move [[ref]] as usize (PointerExposeAddress);
+    // CHECK: [[x:_.*]] = move [[ref]] as usize (PointerExposeProvenance);
     // CHECK: = read([[x]])
     const FOO: &i32 = &1;
     let x = FOO as *const i32 as usize;
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
index cde0cb32f75..e5786bcf701 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
@@ -14,9 +14,9 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = main as fn() (PointerCoercion(ReifyFnPointer));
-          _2 = move _3 as usize (PointerExposeAddress);
+          _2 = move _3 as usize (PointerExposeProvenance);
           StorageDead(_3);
-          _1 = move _2 as *const fn() (PointerFromExposedAddress);
+          _1 = move _2 as *const fn() (PointerWithExposedProvenance);
           StorageDead(_2);
           StorageDead(_1);
           _0 = const ();
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.rs b/tests/mir-opt/const_prop/reify_fn_ptr.rs
index ad73b084219..55dca24f3d2 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.rs
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.rs
@@ -4,7 +4,7 @@
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: [[ptr:_.*]] = main as fn() (PointerCoercion(ReifyFnPointer));
-    // CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeAddress);
-    // CHECK: [[back:_.*]] = move [[addr]] as *const fn() (PointerFromExposedAddress);
+    // CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeProvenance);
+    // CHECK: [[back:_.*]] = move [[addr]] as *const fn() (PointerWithExposedProvenance);
     let _ = main as usize as *const fn();
 }
diff --git a/tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff
index 47dfb421ebc..2b38e88ae4c 100644
--- a/tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff
@@ -3,8 +3,6 @@
   
   fn from_char() -> i32 {
       let mut _0: i32;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 'R' as i32 (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff
index 47dfb421ebc..2b38e88ae4c 100644
--- a/tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff
@@ -3,8 +3,6 @@
   
   fn from_char() -> i32 {
       let mut _0: i32;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 'R' as i32 (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff
index f0c6f55f775..45c48e9046e 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_bool() -> bool {
       let mut _0: bool;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const -1_i8 as bool (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff
index f0c6f55f775..45c48e9046e 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_bool() -> bool {
       let mut _0: bool;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const -1_i8 as bool (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff
index 03a7706401f..b4fe64d0aff 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const core::num::<impl i32>::MAX as char (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff
index 03a7706401f..b4fe64d0aff 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const core::num::<impl i32>::MAX as char (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff
index 5e0c076b981..ab3481a3be5 100644
--- a/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff
@@ -4,8 +4,6 @@
   fn less_as_i8() -> i8 {
       let mut _0: i8;
       let mut _1: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff
index 5e0c076b981..ab3481a3be5 100644
--- a/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff
@@ -4,8 +4,6 @@
   fn less_as_i8() -> i8 {
       let mut _0: i8;
       let mut _1: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff
index c6a428019d8..febb6bfb0a4 100644
--- a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff
@@ -5,8 +5,6 @@
       let mut _0: u32;
       let mut _1: undef_union_as_integer::Union32;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff
index c6a428019d8..febb6bfb0a4 100644
--- a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff
@@ -5,8 +5,6 @@
       let mut _0: u32;
       let mut _1: undef_union_as_integer::Union32;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
index 2ef83abfac0..7a289563c50 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
index 2ef83abfac0..7a289563c50 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff
index b2e91014625..3364782022d 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff
index b2e91014625..3364782022d 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff
index 0ff31b1a981..a7020793237 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff
index 0ff31b1a981..a7020793237 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff
index 430d16c97a6..d44b0872035 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff
@@ -7,8 +7,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff
index 430d16c97a6..d44b0872035 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff
@@ -7,8 +7,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff
index f9d002f96ab..069ff906ec5 100644
--- a/tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff
@@ -3,8 +3,6 @@
   
   fn valid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 82_u32 as char (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff
index f9d002f96ab..069ff906ec5 100644
--- a/tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff
@@ -3,8 +3,6 @@
   
   fn valid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 82_u32 as char (Transmute);
diff --git a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-abort.diff
index ffb0c4b23fb..ef30ac2fc8c 100644
--- a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-abort.diff
+++ b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-abort.diff
@@ -14,13 +14,11 @@
           scope 2 {
               debug b => _3;
               let _5: *mut u8;
-              scope 4 {
+              scope 3 {
 -                 debug c => _5;
 +                 debug c => _2;
               }
           }
-          scope 3 {
-          }
       }
   
       bb0: {
diff --git a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff
index 66a0f49cfb9..a743a3e829a 100644
--- a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff
@@ -14,13 +14,11 @@
           scope 2 {
               debug b => _3;
               let _5: *mut u8;
-              scope 4 {
+              scope 3 {
 -                 debug c => _5;
 +                 debug c => _2;
               }
           }
-          scope 3 {
-          }
       }
   
       bb0: {
diff --git a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-abort.diff
index 0777a913523..2de6f85ce64 100644
--- a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-abort.diff
+++ b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-abort.diff
@@ -13,13 +13,11 @@
           scope 2 {
               debug b => _3;
               let _4: *mut u8;
-              scope 4 {
+              scope 3 {
 -                 debug c => _4;
 +                 debug c => _2;
               }
           }
-          scope 3 {
-          }
       }
   
       bb0: {
diff --git a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff
index f5a512b8995..2afec4898bc 100644
--- a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff
@@ -13,13 +13,11 @@
           scope 2 {
               debug b => _3;
               let _4: *mut u8;
-              scope 4 {
+              scope 3 {
 -                 debug c => _4;
 +                 debug c => _2;
               }
           }
-          scope 3 {
-          }
       }
   
       bb0: {
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
index 21cf745b680..44e73b56098 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
index ee58a974480..6cef8b692ba 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
index 9fc9c8ed409..6efccded993 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
index 30d93347afd..a705d0064cb 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
index 3a46edbc849..f9c854ca3f4 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
index 3c71214c35f..333726689d7 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
index 4557e7b26d6..e1841760077 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
index 5ab2d5e0fdc..7aa02556ec5 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff
index 9b0093c454e..a5e40990751 100644
--- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff
@@ -9,14 +9,12 @@
       let mut _5: *mut u8;
       scope 1 {
           debug x => _1;
+          let _3: *mut u8;
           let _6: u8;
           scope 2 {
-              let _3: *mut u8;
-              scope 3 {
-                  debug p => _3;
-              }
+              debug p => _3;
           }
-          scope 4 {
+          scope 3 {
               debug x1 => _6;
           }
       }
diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff
index 635a214251b..ce2178ddbee 100644
--- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff
@@ -9,14 +9,12 @@
       let mut _5: *mut u8;
       scope 1 {
           debug x => _1;
+          let _3: *mut u8;
           let _6: u8;
           scope 2 {
-              let _3: *mut u8;
-              scope 3 {
-                  debug p => _3;
-              }
+              debug p => _3;
           }
-          scope 4 {
+          scope 3 {
               debug x1 => _6;
           }
       }
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff
index 52f096ac0e4..a5529253762 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff
@@ -3,8 +3,6 @@
   
   fn from_char() -> i32 {
       let mut _0: i32;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 'R' as i32 (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff
index 52f096ac0e4..a5529253762 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff
@@ -3,8 +3,6 @@
   
   fn from_char() -> i32 {
       let mut _0: i32;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 'R' as i32 (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff
index 3972eb209a1..a66d8dbe844 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_bool() -> bool {
       let mut _0: bool;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const -1_i8 as bool (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff
index 3972eb209a1..a66d8dbe844 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_bool() -> bool {
       let mut _0: bool;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const -1_i8 as bool (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff
index dd737017ffd..4f3f3e03d75 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const core::num::<impl i32>::MAX as char (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff
index dd737017ffd..4f3f3e03d75 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const core::num::<impl i32>::MAX as char (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
index 6091e169e8e..44dd4017409 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
@@ -4,8 +4,6 @@
   fn less_as_i8() -> i8 {
       let mut _0: i8;
       let mut _1: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
index 6091e169e8e..44dd4017409 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
@@ -4,8 +4,6 @@
   fn less_as_i8() -> i8 {
       let mut _0: i8;
       let mut _1: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
index fb28aa8f6d9..14a34a1ce38 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
@@ -5,8 +5,6 @@
       let mut _0: u32;
       let mut _1: undef_union_as_integer::Union32;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
index fb28aa8f6d9..14a34a1ce38 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
@@ -5,8 +5,6 @@
       let mut _0: u32;
       let mut _1: undef_union_as_integer::Union32;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
index 5d17c47ae66..258e2b454eb 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
index 5d17c47ae66..258e2b454eb 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
index c8d4d6edba1..a0b4fb2f5e4 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
index c8d4d6edba1..a0b4fb2f5e4 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff
index 2ffaeea72db..ef461423c32 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff
index 2ffaeea72db..ef461423c32 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff
index 31fcaafc5bc..c8910029a03 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff
@@ -7,8 +7,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff
index 31fcaafc5bc..c8910029a03 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff
@@ -7,8 +7,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff
index 402ef754a64..580c5044bb8 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff
@@ -3,8 +3,6 @@
   
   fn valid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 82_u32 as char (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff
index 402ef754a64..580c5044bb8 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff
@@ -3,8 +3,6 @@
   
   fn valid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 82_u32 as char (Transmute);
diff --git a/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
index 9b0dc6b6af6..56d5c24ae1d 100644
--- a/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
+++ b/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
@@ -19,12 +19,12 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = _1;
-          _2 = move _3 as usize (PointerExposeAddress);
+          _2 = move _3 as usize (PointerExposeProvenance);
           StorageDead(_3);
           StorageLive(_4);
           StorageLive(_5);
           _5 = _1;
-          _4 = move _5 as isize (PointerExposeAddress);
+          _4 = move _5 as isize (PointerExposeProvenance);
           StorageDead(_5);
           _0 = const ();
           StorageDead(_4);
diff --git a/tests/mir-opt/dead-store-elimination/provenance_soundness.rs b/tests/mir-opt/dead-store-elimination/provenance_soundness.rs
index 96268cd957e..20517a00489 100644
--- a/tests/mir-opt/dead-store-elimination/provenance_soundness.rs
+++ b/tests/mir-opt/dead-store-elimination/provenance_soundness.rs
@@ -5,8 +5,8 @@
 // EMIT_MIR provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
 fn pointer_to_int(p: *mut i32) {
     // CHECK-LABEL: fn pointer_to_int(
-    // CHECK: {{_.*}} = {{.*}} as usize (PointerExposeAddress);
-    // CHECK: {{_.*}} = {{.*}} as isize (PointerExposeAddress);
+    // CHECK: {{_.*}} = {{.*}} as usize (PointerExposeProvenance);
+    // CHECK: {{_.*}} = {{.*}} as isize (PointerExposeProvenance);
     let _x = p as usize;
     let _y = p as isize;
 }
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
index 0af3faf28f0..570ec129f06 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
@@ -8,13 +8,11 @@
       let mut _3: u32;
       scope 1 {
           debug un => _1;
-          scope 2 {
-          }
-          scope 4 (inlined std::mem::drop::<u32>) {
+          scope 3 (inlined std::mem::drop::<u32>) {
               debug _x => _3;
           }
       }
-      scope 3 (inlined val) {
+      scope 2 (inlined val) {
       }
   
       bb0: {
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
index 0af3faf28f0..570ec129f06 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
@@ -8,13 +8,11 @@
       let mut _3: u32;
       scope 1 {
           debug un => _1;
-          scope 2 {
-          }
-          scope 4 (inlined std::mem::drop::<u32>) {
+          scope 3 (inlined std::mem::drop::<u32>) {
               debug _x => _3;
           }
       }
-      scope 3 (inlined val) {
+      scope 2 (inlined val) {
       }
   
       bb0: {
diff --git a/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff b/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff
index 46bf13985da..906835530d8 100644
--- a/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff
@@ -37,17 +37,9 @@
           debug z => _8;
           let _13: *mut u32;
           scope 2 {
-          }
-          scope 3 {
-          }
-          scope 4 {
               debug z => _13;
               let _18: &u32;
-              scope 5 {
-              }
-              scope 6 {
-              }
-              scope 7 {
+              scope 3 {
                   debug z => _18;
               }
           }
diff --git a/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff b/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff
index 3e731ead859..006b5da646c 100644
--- a/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff
@@ -37,17 +37,9 @@
           debug z => _8;
           let _13: *mut u32;
           scope 2 {
-          }
-          scope 3 {
-          }
-          scope 4 {
               debug z => _13;
               let _18: &u32;
-              scope 5 {
-              }
-              scope 6 {
-              }
-              scope 7 {
+              scope 3 {
                   debug z => _18;
               }
           }
diff --git a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff
index f3f9073909e..2389d98b5b3 100644
--- a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff
@@ -69,17 +69,15 @@
                   debug u => _29;
                   let _41: &*const u8;
                   let _42: &*const u8;
-                  scope 7 {
+                  scope 6 {
                       debug left_val => _41;
                       debug right_val => _42;
                       let _47: core::panicking::AssertKind;
-                      scope 8 {
+                      scope 7 {
                           debug kind => _47;
                       }
                   }
               }
-              scope 6 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff
index 383152cce5e..50715d748e7 100644
--- a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff
@@ -69,17 +69,15 @@
                   debug u => _29;
                   let _41: &*const u8;
                   let _42: &*const u8;
-                  scope 7 {
+                  scope 6 {
                       debug left_val => _41;
                       debug right_val => _42;
                       let _47: core::panicking::AssertKind;
-                      scope 8 {
+                      scope 7 {
                           debug kind => _47;
                       }
                   }
               }
-              scope 6 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff
index 3ecd4650d81..ba9e507560d 100644
--- a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff
@@ -175,18 +175,16 @@
           let _135: &mut u64;
           scope 2 {
               debug b => _135;
+              let _145: *const u64;
               let _163: &u64;
               scope 3 {
-                  let _145: *const u64;
+                  debug c => _145;
+                  let _154: *mut u64;
                   scope 4 {
-                      debug c => _145;
-                      let _154: *mut u64;
-                      scope 5 {
-                          debug d => _154;
-                      }
+                      debug d => _154;
                   }
               }
-              scope 6 {
+              scope 5 {
                   debug e => _163;
               }
           }
diff --git a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff
index bf448280b1e..41c01536130 100644
--- a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff
@@ -175,18 +175,16 @@
           let _135: &mut u64;
           scope 2 {
               debug b => _135;
+              let _145: *const u64;
               let _163: &u64;
               scope 3 {
-                  let _145: *const u64;
+                  debug c => _145;
+                  let _154: *mut u64;
                   scope 4 {
-                      debug c => _145;
-                      let _154: *mut u64;
-                      scope 5 {
-                          debug d => _154;
-                      }
+                      debug d => _154;
                   }
               }
-              scope 6 {
+              scope 5 {
                   debug e => _163;
               }
           }
diff --git a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff
index 11cd43fc0e0..07c4c7663c1 100644
--- a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff
@@ -33,13 +33,9 @@
       scope 1 {
           debug a => _1;
           let _3: *const [u8];
-          scope 3 {
+          scope 2 {
               debug b => _3;
           }
-          scope 4 {
-          }
-      }
-      scope 2 {
       }
   
       bb0: {
diff --git a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff
index c77cd07c60c..df0f93f1077 100644
--- a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff
@@ -33,13 +33,9 @@
       scope 1 {
           debug a => _1;
           let _3: *const [u8];
-          scope 3 {
+          scope 2 {
               debug b => _3;
           }
-          scope 4 {
-          }
-      }
-      scope 2 {
       }
   
       bb0: {
diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff
index 86e6aae1191..c5ee0d9c44d 100644
--- a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff
@@ -7,12 +7,10 @@
       let mut _2: E;
       let mut _3: &U;
       let _4: U;
+      let mut _5: &U;
       scope 1 {
           debug i => _1;
       }
-      scope 2 {
-          let mut _5: &U;
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff
index 86e6aae1191..c5ee0d9c44d 100644
--- a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff
@@ -7,12 +7,10 @@
       let mut _2: E;
       let mut _3: &U;
       let _4: U;
+      let mut _5: &U;
       scope 1 {
           debug i => _1;
       }
-      scope 2 {
-          let mut _5: &U;
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff
index ea9c360aa7b..dc0004105a7 100644
--- a/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff
@@ -8,8 +8,6 @@
 +         let _2: D;
 +         scope 2 {
 +             debug _d => const D;
-+             scope 3 {
-+             }
 +         }
 +     }
   
diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff
index a38b8246bde..859082c3111 100644
--- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff
@@ -15,13 +15,11 @@
 +     }
 +     scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new) {
 +         debug pointer => _3;
-+         scope 4 {
-+             scope 5 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) {
-+                 debug pointer => _3;
-+             }
++         scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) {
++             debug pointer => _3;
 +         }
 +     }
-+     scope 6 (inlined g::{closure#0}) {
++     scope 5 (inlined g::{closure#0}) {
 +         debug a => _5;
 +         let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8};
 +         let mut _7: u32;
diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff
index dc6628ab44c..44b06c34972 100644
--- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff
@@ -15,13 +15,11 @@
 +     }
 +     scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new) {
 +         debug pointer => _3;
-+         scope 4 {
-+             scope 5 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) {
-+                 debug pointer => _3;
-+             }
++         scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) {
++             debug pointer => _3;
 +         }
 +     }
-+     scope 6 (inlined g::{closure#0}) {
++     scope 5 (inlined g::{closure#0}) {
 +         debug a => _5;
 +         let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8};
 +         let mut _7: u32;
diff --git a/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff b/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff
index e38daba27fc..158cc973779 100644
--- a/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff
+++ b/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff
@@ -10,8 +10,6 @@
 +     scope 1 (inlined instruction_set_default) {
 +     }
 +     scope 2 (inlined inline_always_and_using_inline_asm) {
-+         scope 3 {
-+         }
 +     }
   
       bb0: {
diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
index 4fcd49994f0..2a36ccaab11 100644
--- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
@@ -8,18 +8,14 @@
       let _3: ();
       let mut _4: *mut std::vec::Vec<A>;
       let mut _5: *mut std::option::Option<B>;
-      scope 1 {
-+         scope 3 (inlined std::ptr::drop_in_place::<Vec<A>> - shim(Some(Vec<A>))) {
-+             let mut _6: &mut std::vec::Vec<A>;
-+             let mut _7: ();
-+         }
-      }
-      scope 2 {
-+         scope 4 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
-+             let mut _8: isize;
-+             let mut _9: isize;
-+         }
-      }
++     scope 1 (inlined std::ptr::drop_in_place::<Vec<A>> - shim(Some(Vec<A>))) {
++         let mut _6: &mut std::vec::Vec<A>;
++         let mut _7: ();
++     }
++     scope 2 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
++         let mut _8: isize;
++         let mut _9: isize;
++     }
   
       bb0: {
           StorageLive(_3);
diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
index 4270ae00b66..e11561076e6 100644
--- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
@@ -8,14 +8,10 @@
       let _3: ();
       let mut _4: *mut std::vec::Vec<A>;
       let mut _5: *mut std::option::Option<B>;
-      scope 1 {
-      }
-      scope 2 {
-+         scope 3 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
-+             let mut _6: isize;
-+             let mut _7: isize;
-+         }
-      }
++     scope 1 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
++         let mut _6: isize;
++         let mut _7: isize;
++     }
   
       bb0: {
           StorageLive(_3);
diff --git a/tests/mir-opt/inline/unchecked_shifts.rs b/tests/mir-opt/inline/unchecked_shifts.rs
index 12b00e76a11..3c4e73bf7ea 100644
--- a/tests/mir-opt/inline/unchecked_shifts.rs
+++ b/tests/mir-opt/inline/unchecked_shifts.rs
@@ -4,6 +4,9 @@
 
 //@ compile-flags: -Zmir-opt-level=2 -Zinline-mir
 
+// These used to be more interesting when the library had to fix the RHS type.
+// After MCP#693, though, that's the backend's problem, not something in MIR.
+
 // EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff
 // EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir
 pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 {
@@ -12,22 +15,6 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 {
     a.unchecked_shl(b)
 }
 
-// EMIT_MIR unchecked_shifts.unchecked_shr_signed_smaller.Inline.diff
-// EMIT_MIR unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir
-pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 {
-    // CHECK-LABEL: fn unchecked_shr_signed_smaller(
-    // CHECK: (inlined core::num::<impl i16>::unchecked_shr)
-    a.unchecked_shr(b)
-}
-
-// EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.diff
-// EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.mir
-pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 {
-    // CHECK-LABEL: fn unchecked_shl_unsigned_bigger(
-    // CHECK: (inlined core::num::<impl u64>::unchecked_shl)
-    a.unchecked_shl(b)
-}
-
 // EMIT_MIR unchecked_shifts.unchecked_shr_signed_bigger.Inline.diff
 // EMIT_MIR unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.mir
 pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 {
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff
deleted file mode 100644
index 1ab1d01e5fa..00000000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff
+++ /dev/null
@@ -1,36 +0,0 @@
-- // MIR for `unchecked_shl_unsigned_bigger` before Inline
-+ // MIR for `unchecked_shl_unsigned_bigger` after Inline
-  
-  fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 {
-      debug a => _1;
-      debug b => _2;
-      let mut _0: u64;
-      let mut _3: u64;
-      let mut _4: u32;
-+     scope 1 (inlined core::num::<impl u64>::unchecked_shl) {
-+         debug self => _3;
-+         debug rhs => _4;
-+         let mut _5: u64;
-+         scope 2 {
-+         }
-+     }
-  
-      bb0: {
-          StorageLive(_3);
-          _3 = _1;
-          StorageLive(_4);
-          _4 = _2;
--         _0 = core::num::<impl u64>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable];
--     }
-- 
--     bb1: {
-+         StorageLive(_5);
-+         _5 = _4 as u64 (IntToInt);
-+         _0 = ShlUnchecked(_3, move _5);
-+         StorageDead(_5);
-          StorageDead(_4);
-          StorageDead(_3);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff
deleted file mode 100644
index d71b5c4a626..00000000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff
+++ /dev/null
@@ -1,36 +0,0 @@
-- // MIR for `unchecked_shl_unsigned_bigger` before Inline
-+ // MIR for `unchecked_shl_unsigned_bigger` after Inline
-  
-  fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 {
-      debug a => _1;
-      debug b => _2;
-      let mut _0: u64;
-      let mut _3: u64;
-      let mut _4: u32;
-+     scope 1 (inlined core::num::<impl u64>::unchecked_shl) {
-+         debug self => _3;
-+         debug rhs => _4;
-+         let mut _5: u64;
-+         scope 2 {
-+         }
-+     }
-  
-      bb0: {
-          StorageLive(_3);
-          _3 = _1;
-          StorageLive(_4);
-          _4 = _2;
--         _0 = core::num::<impl u64>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue];
--     }
-- 
--     bb1: {
-+         StorageLive(_5);
-+         _5 = _4 as u64 (IntToInt);
-+         _0 = ShlUnchecked(_3, move _5);
-+         StorageDead(_5);
-          StorageDead(_4);
-          StorageDead(_3);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir
deleted file mode 100644
index 65b832497f9..00000000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir
+++ /dev/null
@@ -1,22 +0,0 @@
-// MIR for `unchecked_shl_unsigned_bigger` after PreCodegen
-
-fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 {
-    debug a => _1;
-    debug b => _2;
-    let mut _0: u64;
-    scope 1 (inlined core::num::<impl u64>::unchecked_shl) {
-        debug self => _1;
-        debug rhs => _2;
-        let mut _3: u64;
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_3);
-        _3 = _2 as u64 (IntToInt);
-        _0 = ShlUnchecked(_1, move _3);
-        StorageDead(_3);
-        return;
-    }
-}
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir
deleted file mode 100644
index 65b832497f9..00000000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir
+++ /dev/null
@@ -1,22 +0,0 @@
-// MIR for `unchecked_shl_unsigned_bigger` after PreCodegen
-
-fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 {
-    debug a => _1;
-    debug b => _2;
-    let mut _0: u64;
-    scope 1 (inlined core::num::<impl u64>::unchecked_shl) {
-        debug self => _1;
-        debug rhs => _2;
-        let mut _3: u64;
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_3);
-        _3 = _2 as u64 (IntToInt);
-        _0 = ShlUnchecked(_1, move _3);
-        StorageDead(_3);
-        return;
-    }
-}
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff
index d052219661b..cc1b8b9b70f 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff
@@ -10,10 +10,6 @@
 +     scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
 +         debug self => _3;
 +         debug rhs => _4;
-+         let mut _5: u16;
-+         let mut _6: bool;
-+         scope 2 {
-+         }
 +     }
   
       bb0: {
@@ -25,14 +21,7 @@
 -     }
 - 
 -     bb1: {
-+         StorageLive(_5);
-+         StorageLive(_6);
-+         _6 = Le(_4, const 65535_u32);
-+         assume(move _6);
-+         StorageDead(_6);
-+         _5 = _4 as u16 (IntToInt);
-+         _0 = ShlUnchecked(_3, move _5);
-+         StorageDead(_5);
++         _0 = ShlUnchecked(_3, _4);
           StorageDead(_4);
           StorageDead(_3);
           return;
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff
index 67a5ac2483b..f244f378bce 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff
@@ -10,10 +10,6 @@
 +     scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
 +         debug self => _3;
 +         debug rhs => _4;
-+         let mut _5: u16;
-+         let mut _6: bool;
-+         scope 2 {
-+         }
 +     }
   
       bb0: {
@@ -25,14 +21,7 @@
 -     }
 - 
 -     bb1: {
-+         StorageLive(_5);
-+         StorageLive(_6);
-+         _6 = Le(_4, const 65535_u32);
-+         assume(move _6);
-+         StorageDead(_6);
-+         _5 = _4 as u16 (IntToInt);
-+         _0 = ShlUnchecked(_3, move _5);
-+         StorageDead(_5);
++         _0 = ShlUnchecked(_3, _4);
           StorageDead(_4);
           StorageDead(_3);
           return;
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir
index f9dff62e0c8..c96983c18cb 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir
@@ -7,21 +7,10 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 {
     scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
         debug self => _1;
         debug rhs => _2;
-        let mut _3: bool;
-        let mut _4: u16;
-        scope 2 {
-        }
     }
 
     bb0: {
-        StorageLive(_4);
-        StorageLive(_3);
-        _3 = Le(_2, const 65535_u32);
-        assume(move _3);
-        StorageDead(_3);
-        _4 = _2 as u16 (IntToInt);
-        _0 = ShlUnchecked(_1, move _4);
-        StorageDead(_4);
+        _0 = ShlUnchecked(_1, _2);
         return;
     }
 }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir
index f9dff62e0c8..c96983c18cb 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir
@@ -7,21 +7,10 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 {
     scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
         debug self => _1;
         debug rhs => _2;
-        let mut _3: bool;
-        let mut _4: u16;
-        scope 2 {
-        }
     }
 
     bb0: {
-        StorageLive(_4);
-        StorageLive(_3);
-        _3 = Le(_2, const 65535_u32);
-        assume(move _3);
-        StorageDead(_3);
-        _4 = _2 as u16 (IntToInt);
-        _0 = ShlUnchecked(_1, move _4);
-        StorageDead(_4);
+        _0 = ShlUnchecked(_1, _2);
         return;
     }
 }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff
index 1e83fec4f3d..74518db370f 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff
@@ -10,9 +10,6 @@
 +     scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
 +         debug self => _3;
 +         debug rhs => _4;
-+         let mut _5: i64;
-+         scope 2 {
-+         }
 +     }
   
       bb0: {
@@ -24,10 +21,7 @@
 -     }
 - 
 -     bb1: {
-+         StorageLive(_5);
-+         _5 = _4 as i64 (IntToInt);
-+         _0 = ShrUnchecked(_3, move _5);
-+         StorageDead(_5);
++         _0 = ShrUnchecked(_3, _4);
           StorageDead(_4);
           StorageDead(_3);
           return;
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff
index 6aafb61dc55..aab04624f6c 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff
@@ -10,9 +10,6 @@
 +     scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
 +         debug self => _3;
 +         debug rhs => _4;
-+         let mut _5: i64;
-+         scope 2 {
-+         }
 +     }
   
       bb0: {
@@ -24,10 +21,7 @@
 -     }
 - 
 -     bb1: {
-+         StorageLive(_5);
-+         _5 = _4 as i64 (IntToInt);
-+         _0 = ShrUnchecked(_3, move _5);
-+         StorageDead(_5);
++         _0 = ShrUnchecked(_3, _4);
           StorageDead(_4);
           StorageDead(_3);
           return;
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir
index 7524ec4970e..1dd8cb27314 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir
@@ -7,16 +7,10 @@ fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 {
     scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
         debug self => _1;
         debug rhs => _2;
-        let mut _3: i64;
-        scope 2 {
-        }
     }
 
     bb0: {
-        StorageLive(_3);
-        _3 = _2 as i64 (IntToInt);
-        _0 = ShrUnchecked(_1, move _3);
-        StorageDead(_3);
+        _0 = ShrUnchecked(_1, _2);
         return;
     }
 }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir
index 7524ec4970e..1dd8cb27314 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir
@@ -7,16 +7,10 @@ fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 {
     scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
         debug self => _1;
         debug rhs => _2;
-        let mut _3: i64;
-        scope 2 {
-        }
     }
 
     bb0: {
-        StorageLive(_3);
-        _3 = _2 as i64 (IntToInt);
-        _0 = ShrUnchecked(_1, move _3);
-        StorageDead(_3);
+        _0 = ShrUnchecked(_1, _2);
         return;
     }
 }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff
deleted file mode 100644
index 15b36b284de..00000000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff
+++ /dev/null
@@ -1,41 +0,0 @@
-- // MIR for `unchecked_shr_signed_smaller` before Inline
-+ // MIR for `unchecked_shr_signed_smaller` after Inline
-  
-  fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
-      debug a => _1;
-      debug b => _2;
-      let mut _0: i16;
-      let mut _3: i16;
-      let mut _4: u32;
-+     scope 1 (inlined core::num::<impl i16>::unchecked_shr) {
-+         debug self => _3;
-+         debug rhs => _4;
-+         let mut _5: i16;
-+         let mut _6: bool;
-+         scope 2 {
-+         }
-+     }
-  
-      bb0: {
-          StorageLive(_3);
-          _3 = _1;
-          StorageLive(_4);
-          _4 = _2;
--         _0 = core::num::<impl i16>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable];
--     }
-- 
--     bb1: {
-+         StorageLive(_5);
-+         StorageLive(_6);
-+         _6 = Le(_4, const 32767_u32);
-+         assume(move _6);
-+         StorageDead(_6);
-+         _5 = _4 as i16 (IntToInt);
-+         _0 = ShrUnchecked(_3, move _5);
-+         StorageDead(_5);
-          StorageDead(_4);
-          StorageDead(_3);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff
deleted file mode 100644
index 8629f92dbad..00000000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff
+++ /dev/null
@@ -1,41 +0,0 @@
-- // MIR for `unchecked_shr_signed_smaller` before Inline
-+ // MIR for `unchecked_shr_signed_smaller` after Inline
-  
-  fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
-      debug a => _1;
-      debug b => _2;
-      let mut _0: i16;
-      let mut _3: i16;
-      let mut _4: u32;
-+     scope 1 (inlined core::num::<impl i16>::unchecked_shr) {
-+         debug self => _3;
-+         debug rhs => _4;
-+         let mut _5: i16;
-+         let mut _6: bool;
-+         scope 2 {
-+         }
-+     }
-  
-      bb0: {
-          StorageLive(_3);
-          _3 = _1;
-          StorageLive(_4);
-          _4 = _2;
--         _0 = core::num::<impl i16>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue];
--     }
-- 
--     bb1: {
-+         StorageLive(_5);
-+         StorageLive(_6);
-+         _6 = Le(_4, const 32767_u32);
-+         assume(move _6);
-+         StorageDead(_6);
-+         _5 = _4 as i16 (IntToInt);
-+         _0 = ShrUnchecked(_3, move _5);
-+         StorageDead(_5);
-          StorageDead(_4);
-          StorageDead(_3);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir
deleted file mode 100644
index 65fa0d956c0..00000000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir
+++ /dev/null
@@ -1,27 +0,0 @@
-// MIR for `unchecked_shr_signed_smaller` after PreCodegen
-
-fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
-    debug a => _1;
-    debug b => _2;
-    let mut _0: i16;
-    scope 1 (inlined core::num::<impl i16>::unchecked_shr) {
-        debug self => _1;
-        debug rhs => _2;
-        let mut _3: bool;
-        let mut _4: i16;
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_4);
-        StorageLive(_3);
-        _3 = Le(_2, const 32767_u32);
-        assume(move _3);
-        StorageDead(_3);
-        _4 = _2 as i16 (IntToInt);
-        _0 = ShrUnchecked(_1, move _4);
-        StorageDead(_4);
-        return;
-    }
-}
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir
deleted file mode 100644
index 65fa0d956c0..00000000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir
+++ /dev/null
@@ -1,27 +0,0 @@
-// MIR for `unchecked_shr_signed_smaller` after PreCodegen
-
-fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
-    debug a => _1;
-    debug b => _2;
-    let mut _0: i16;
-    scope 1 (inlined core::num::<impl i16>::unchecked_shr) {
-        debug self => _1;
-        debug rhs => _2;
-        let mut _3: bool;
-        let mut _4: i16;
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_4);
-        StorageLive(_3);
-        _3 = Le(_2, const 32767_u32);
-        assume(move _3);
-        StorageDead(_3);
-        _4 = _2 as i16 (IntToInt);
-        _0 = ShrUnchecked(_1, move _4);
-        StorageDead(_4);
-        return;
-    }
-}
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
index 028040edc85..814eda10459 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
@@ -11,15 +11,11 @@
 +         scope 2 {
 +             debug val => _0;
 +         }
-+         scope 3 {
-+             scope 4 (inlined unreachable_unchecked) {
-+                 let mut _4: bool;
-+                 let _5: ();
-+                 scope 5 {
-+                 }
-+                 scope 6 (inlined core::ub_checks::check_language_ub) {
-+                     scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
-+                     }
++         scope 3 (inlined unreachable_unchecked) {
++             let mut _4: bool;
++             let _5: ();
++             scope 4 (inlined core::ub_checks::check_language_ub) {
++                 scope 5 (inlined core::ub_checks::check_language_ub::runtime) {
 +                 }
 +             }
 +         }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
index 484fd37248c..d5d69074382 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
@@ -11,15 +11,11 @@
 +         scope 2 {
 +             debug val => _0;
 +         }
-+         scope 3 {
-+             scope 4 (inlined unreachable_unchecked) {
-+                 let mut _4: bool;
-+                 let _5: ();
-+                 scope 5 {
-+                 }
-+                 scope 6 (inlined core::ub_checks::check_language_ub) {
-+                     scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
-+                     }
++         scope 3 (inlined unreachable_unchecked) {
++             let mut _4: bool;
++             let _5: ();
++             scope 4 (inlined core::ub_checks::check_language_ub) {
++                 scope 5 (inlined core::ub_checks::check_language_ub::runtime) {
 +                 }
 +             }
 +         }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
index d629336d385..7c24a97166c 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
@@ -9,13 +9,9 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
         scope 2 {
             debug val => _0;
         }
-        scope 3 {
-            scope 4 (inlined unreachable_unchecked) {
-                scope 5 {
-                }
-                scope 6 (inlined core::ub_checks::check_language_ub) {
-                    scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
-                    }
+        scope 3 (inlined unreachable_unchecked) {
+            scope 4 (inlined core::ub_checks::check_language_ub) {
+                scope 5 (inlined core::ub_checks::check_language_ub::runtime) {
                 }
             }
         }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
index d629336d385..7c24a97166c 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
@@ -9,13 +9,9 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
         scope 2 {
             debug val => _0;
         }
-        scope 3 {
-            scope 4 (inlined unreachable_unchecked) {
-                scope 5 {
-                }
-                scope 6 (inlined core::ub_checks::check_language_ub) {
-                    scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
-                    }
+        scope 3 (inlined unreachable_unchecked) {
+            scope 4 (inlined core::ub_checks::check_language_ub) {
+                scope 5 (inlined core::ub_checks::check_language_ub::runtime) {
                 }
             }
         }
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
index 0243e31cb1a..f8cceacd7e6 100644
--- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
@@ -18,9 +18,9 @@
           let _4: std::pin::Pin<&mut {async fn body of ActionPermit<'_, T>::perform()}>;
           scope 2 {
               debug fut => _4;
-              scope 4 {
+              scope 3 {
               }
-+             scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
++             scope 6 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
 +                 debug _task_context => _31;
 +                 debug self => ((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})).0: ActionPermit<'_, T>);
 +                 let _11: ActionPermit<'_, T>;
@@ -51,32 +51,28 @@
 +                 let mut _38: &mut {async fn body of ActionPermit<'_, T>::perform()};
 +                 let mut _39: &mut {async fn body of ActionPermit<'_, T>::perform()};
 +                 let mut _40: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 scope 8 {
++                 scope 7 {
 +                     debug self => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).0: ActionPermit<'_, T>);
 +                     let mut _15: std::future::Ready<()>;
-+                     scope 9 {
++                     scope 8 {
 +                         debug __awaitee => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).1: std::future::Ready<()>);
 +                         let _26: ();
-+                         scope 10 {
-+                         }
-+                         scope 11 {
++                         scope 9 {
 +                             debug result => _26;
 +                         }
 +                     }
-+                     scope 12 (inlined ready::<()>) {
++                     scope 10 (inlined ready::<()>) {
 +                         debug t => _14;
 +                         let mut _41: std::option::Option<()>;
 +                     }
 +                 }
 +             }
           }
-          scope 3 {
-+             scope 6 (inlined Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked) {
-+                 debug pointer => _5;
-+             }
-          }
++         scope 5 (inlined Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked) {
++             debug pointer => _5;
++         }
       }
-+     scope 5 (inlined ActionPermit::<'_, T>::perform) {
++     scope 4 (inlined ActionPermit::<'_, T>::perform) {
 +         debug self => _3;
 +     }
   
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
index 96a93cdda3d..fd080d22d3a 100644
--- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
@@ -18,9 +18,9 @@
           let _4: std::pin::Pin<&mut {async fn body of ActionPermit<'_, T>::perform()}>;
           scope 2 {
               debug fut => _4;
-              scope 4 {
+              scope 3 {
               }
-+             scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
++             scope 6 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
 +                 debug _task_context => _31;
 +                 debug self => ((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})).0: ActionPermit<'_, T>);
 +                 let _11: ActionPermit<'_, T>;
@@ -53,32 +53,28 @@
 +                 let mut _40: &mut {async fn body of ActionPermit<'_, T>::perform()};
 +                 let mut _41: &mut {async fn body of ActionPermit<'_, T>::perform()};
 +                 let mut _42: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 scope 8 {
++                 scope 7 {
 +                     debug self => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).0: ActionPermit<'_, T>);
 +                     let mut _15: std::future::Ready<()>;
-+                     scope 9 {
++                     scope 8 {
 +                         debug __awaitee => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).1: std::future::Ready<()>);
 +                         let _26: ();
-+                         scope 10 {
-+                         }
-+                         scope 11 {
++                         scope 9 {
 +                             debug result => _26;
 +                         }
 +                     }
-+                     scope 12 (inlined ready::<()>) {
++                     scope 10 (inlined ready::<()>) {
 +                         debug t => _14;
 +                         let mut _43: std::option::Option<()>;
 +                     }
 +                 }
 +             }
           }
-          scope 3 {
-+             scope 6 (inlined Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked) {
-+                 debug pointer => _5;
-+             }
-          }
++         scope 5 (inlined Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked) {
++             debug pointer => _5;
++         }
       }
-+     scope 5 (inlined ActionPermit::<'_, T>::perform) {
++     scope 4 (inlined ActionPermit::<'_, T>::perform) {
 +         debug self => _3;
 +     }
   
diff --git a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify.diff b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify.diff
index f3402fde05b..6d6c9c9a7a1 100644
--- a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify.diff
+++ b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify.diff
@@ -5,23 +5,17 @@
       debug x => _1;
       let mut _0: i32;
       let mut _2: std::option::Option<i32>;
-      scope 1 {
-          scope 2 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
-              debug self => _2;
-              let mut _3: isize;
-              scope 3 {
-                  debug val => _0;
-              }
-              scope 4 {
-                  scope 5 (inlined unreachable_unchecked) {
-                      let mut _4: bool;
-                      let _5: ();
-                      scope 6 {
-                      }
-                      scope 7 (inlined core::ub_checks::check_language_ub) {
-                          scope 8 (inlined core::ub_checks::check_language_ub::runtime) {
-                          }
-                      }
+      scope 1 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
+          debug self => _2;
+          let mut _3: isize;
+          scope 2 {
+              debug val => _0;
+          }
+          scope 3 (inlined unreachable_unchecked) {
+              let mut _4: bool;
+              let _5: ();
+              scope 4 (inlined core::ub_checks::check_language_ub) {
+                  scope 5 (inlined core::ub_checks::check_language_ub::runtime) {
                   }
               }
           }
diff --git a/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-abort.mir b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-abort.mir
index b4f21240939..53912adc003 100644
--- a/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-abort.mir
+++ b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-abort.mir
@@ -4,8 +4,6 @@ fn main() -> () {
     let mut _0: ();
     let mut _1: !;
     let mut _2: ();
-    scope 1 {
-    }
 
     bb0: {
         StorageLive(_1);
diff --git a/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir
index 1851747f0a6..50416300094 100644
--- a/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir
+++ b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir
@@ -4,8 +4,6 @@ fn main() -> () {
     let mut _0: ();
     let mut _1: !;
     let mut _2: ();
-    scope 1 {
-    }
 
     bb0: {
         StorageLive(_1);
diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir
index 91dee82fde0..3104baa5fdb 100644
--- a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir
+++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir
@@ -15,15 +15,13 @@ fn test() -> Option<Box<u32>> {
     let mut _11: std::option::Option<std::convert::Infallible>;
     let _12: u32;
     scope 1 {
-    }
-    scope 2 {
         debug residual => _9;
-        scope 3 {
+        scope 2 {
         }
     }
-    scope 4 {
+    scope 3 {
         debug val => _12;
-        scope 5 {
+        scope 4 {
         }
     }
 
diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir
index ff7fc74ff61..da33c830115 100644
--- a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir
+++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir
@@ -15,15 +15,13 @@ fn test() -> Option<Box<u32>> {
     let mut _11: std::option::Option<std::convert::Infallible>;
     let _12: u32;
     scope 1 {
-    }
-    scope 2 {
         debug residual => _9;
-        scope 3 {
+        scope 2 {
         }
     }
-    scope 4 {
+    scope 3 {
         debug val => _12;
-        scope 5 {
+        scope 4 {
         }
     }
 
diff --git a/tests/mir-opt/issue_72181.main.built.after.mir b/tests/mir-opt/issue_72181.main.built.after.mir
index cff20702bf7..fa101512d72 100644
--- a/tests/mir-opt/issue_72181.main.built.after.mir
+++ b/tests/mir-opt/issue_72181.main.built.after.mir
@@ -15,8 +15,6 @@ fn main() -> () {
             debug f => _2;
             scope 3 {
             }
-            scope 4 {
-            }
         }
     }
 
diff --git a/tests/mir-opt/issue_72181_1.main.built.after.mir b/tests/mir-opt/issue_72181_1.main.built.after.mir
index d35aada95f8..ae0dc9a0b6a 100644
--- a/tests/mir-opt/issue_72181_1.main.built.after.mir
+++ b/tests/mir-opt/issue_72181_1.main.built.after.mir
@@ -14,8 +14,6 @@ fn main() -> () {
     scope 1 {
         debug v => _2;
     }
-    scope 2 {
-    }
 
     bb0: {
         StorageLive(_2);
diff --git a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
index f11c993340f..25ed1b4d0c7 100644
--- a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
+++ b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
@@ -10,15 +10,11 @@
       let mut _6: u32;
       scope 1 {
           debug dwords => _2;
-          scope 3 {
+          scope 2 {
               debug ip => _4;
               let _4: u32;
-              scope 4 {
-              }
           }
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-abort.diff
index 80a42263643..e9d4352014f 100644
--- a/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-abort.diff
+++ b/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-abort.diff
@@ -12,8 +12,6 @@
           let _2: *mut i32;
           scope 2 {
               debug a => _2;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-unwind.diff
index 80a42263643..e9d4352014f 100644
--- a/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-unwind.diff
+++ b/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-unwind.diff
@@ -12,8 +12,6 @@
           let _2: *mut i32;
           scope 2 {
               debug a => _2;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff
index f9f73bf991d..633a344a2ed 100644
--- a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff
@@ -14,8 +14,6 @@
           let _5: *const [u8];
           scope 2 {
               debug arr => _5;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff
index f9f73bf991d..633a344a2ed 100644
--- a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff
@@ -14,8 +14,6 @@
           let _5: *const [u8];
           scope 2 {
               debug arr => _5;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-abort.diff
index 79635f23e8e..6c1f457cb5f 100644
--- a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-abort.diff
@@ -4,8 +4,6 @@
   fn assume() -> () {
       let mut _0: ();
       let _1: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-unwind.diff
index 79635f23e8e..6c1f457cb5f 100644
--- a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-unwind.diff
@@ -4,8 +4,6 @@
   fn assume() -> () {
       let mut _0: ();
       let _1: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
index 6de5f2c4f07..96b66af66a2 100644
--- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
@@ -18,8 +18,6 @@
           let mut _2: ();
           scope 2 {
               debug dst => _2;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
index 6de5f2c4f07..96b66af66a2 100644
--- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
@@ -18,8 +18,6 @@
           let mut _2: ();
           scope 2 {
               debug dst => _2;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-abort.diff
index 147c48a3c01..781104be290 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       debug r => _1;
       let mut _0: i32;
       let mut _2: *const i32;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-unwind.diff
index 147c48a3c01..781104be290 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       debug r => _1;
       let mut _0: i32;
       let mut _2: *const i32;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff
index b2cf3cc1cca..56c357b3776 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       debug r => _1;
       let mut _0: Never;
       let mut _2: *const Never;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff
index b2cf3cc1cca..56c357b3776 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       debug r => _1;
       let mut _0: Never;
       let mut _2: *const Never;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs
index 278ddfce1c3..08366417d7c 100644
--- a/tests/mir-opt/lower_intrinsics.rs
+++ b/tests/mir-opt/lower_intrinsics.rs
@@ -16,7 +16,7 @@ pub fn wrapping(a: i32, b: i32) {
 }
 
 // EMIT_MIR lower_intrinsics.unchecked.LowerIntrinsics.diff
-pub unsafe fn unchecked(a: i32, b: i32) {
+pub unsafe fn unchecked(a: i32, b: i32, c: u32) {
     // CHECK-LABEL: fn unchecked(
     // CHECK: {{_.*}} = AddUnchecked(
     // CHECK: {{_.*}} = SubUnchecked(
@@ -25,6 +25,8 @@ pub unsafe fn unchecked(a: i32, b: i32) {
     // CHECK: {{_.*}} = Rem(
     // CHECK: {{_.*}} = ShlUnchecked(
     // CHECK: {{_.*}} = ShrUnchecked(
+    // CHECK: {{_.*}} = ShlUnchecked(
+    // CHECK: {{_.*}} = ShrUnchecked(
     let _a = core::intrinsics::unchecked_add(a, b);
     let _b = core::intrinsics::unchecked_sub(a, b);
     let _c = core::intrinsics::unchecked_mul(a, b);
@@ -32,6 +34,8 @@ pub unsafe fn unchecked(a: i32, b: i32) {
     let _y = core::intrinsics::unchecked_rem(a, b);
     let _i = core::intrinsics::unchecked_shl(a, b);
     let _j = core::intrinsics::unchecked_shr(a, b);
+    let _k = core::intrinsics::unchecked_shl(a, c);
+    let _l = core::intrinsics::unchecked_shr(a, c);
 }
 
 // EMIT_MIR lower_intrinsics.size_of.LowerIntrinsics.diff
@@ -229,3 +233,18 @@ pub unsafe fn ptr_offset(p: *const i32, d: isize) -> *const i32 {
 
     core::intrinsics::offset(p, d)
 }
+
+// EMIT_MIR lower_intrinsics.three_way_compare_char.LowerIntrinsics.diff
+pub fn three_way_compare_char(a: char, b: char) {
+    let _x = core::intrinsics::three_way_compare(a, b);
+}
+
+// EMIT_MIR lower_intrinsics.three_way_compare_signed.LowerIntrinsics.diff
+pub fn three_way_compare_signed(a: i16, b: i16) {
+    core::intrinsics::three_way_compare(a, b);
+}
+
+// EMIT_MIR lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.diff
+pub fn three_way_compare_unsigned(a: u32, b: u32) {
+    let _x = core::intrinsics::three_way_compare(a, b);
+}
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-abort.diff
new file mode 100644
index 00000000000..816d6209715
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-abort.diff
@@ -0,0 +1,34 @@
+- // MIR for `three_way_compare_char` before LowerIntrinsics
++ // MIR for `three_way_compare_char` after LowerIntrinsics
+  
+  fn three_way_compare_char(_1: char, _2: char) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: char;
+      let mut _5: char;
+      scope 1 {
+          debug _x => _3;
+      }
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<char>(move _4, move _5) -> [return: bb1, unwind unreachable];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          _0 = const ();
+          StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff
new file mode 100644
index 00000000000..80b4bd7a2be
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff
@@ -0,0 +1,34 @@
+- // MIR for `three_way_compare_char` before LowerIntrinsics
++ // MIR for `three_way_compare_char` after LowerIntrinsics
+  
+  fn three_way_compare_char(_1: char, _2: char) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: char;
+      let mut _5: char;
+      scope 1 {
+          debug _x => _3;
+      }
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<char>(move _4, move _5) -> [return: bb1, unwind continue];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          _0 = const ();
+          StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-abort.diff
new file mode 100644
index 00000000000..05c20aaa09a
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-abort.diff
@@ -0,0 +1,31 @@
+- // MIR for `three_way_compare_signed` before LowerIntrinsics
++ // MIR for `three_way_compare_signed` after LowerIntrinsics
+  
+  fn three_way_compare_signed(_1: i16, _2: i16) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: i16;
+      let mut _5: i16;
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<i16>(move _4, move _5) -> [return: bb1, unwind unreachable];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff
new file mode 100644
index 00000000000..8a254d02a47
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff
@@ -0,0 +1,31 @@
+- // MIR for `three_way_compare_signed` before LowerIntrinsics
++ // MIR for `three_way_compare_signed` after LowerIntrinsics
+  
+  fn three_way_compare_signed(_1: i16, _2: i16) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: i16;
+      let mut _5: i16;
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<i16>(move _4, move _5) -> [return: bb1, unwind continue];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-abort.diff
new file mode 100644
index 00000000000..437614ec673
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-abort.diff
@@ -0,0 +1,34 @@
+- // MIR for `three_way_compare_unsigned` before LowerIntrinsics
++ // MIR for `three_way_compare_unsigned` after LowerIntrinsics
+  
+  fn three_way_compare_unsigned(_1: u32, _2: u32) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: u32;
+      let mut _5: u32;
+      scope 1 {
+          debug _x => _3;
+      }
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<u32>(move _4, move _5) -> [return: bb1, unwind unreachable];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          _0 = const ();
+          StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff
new file mode 100644
index 00000000000..7d6137979c8
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff
@@ -0,0 +1,34 @@
+- // MIR for `three_way_compare_unsigned` before LowerIntrinsics
++ // MIR for `three_way_compare_unsigned` after LowerIntrinsics
+  
+  fn three_way_compare_unsigned(_1: u32, _2: u32) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: u32;
+      let mut _5: u32;
+      scope 1 {
+          debug _x => _3;
+      }
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<u32>(move _4, move _5) -> [return: bb1, unwind continue];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          _0 = const ();
+          StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff
index 3b4051e4ae2..6e542c4b5a7 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       debug c => _1;
       let mut _0: i8;
       let mut _2: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff
index 3b4051e4ae2..6e542c4b5a7 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       debug c => _1;
       let mut _0: i8;
       let mut _2: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff
index 91276a1b5c4..ab4646370f1 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       debug u => _1;
       let mut _0: *const T;
       let mut _2: &T;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff
index 91276a1b5c4..ab4646370f1 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       debug u => _1;
       let mut _0: *const T;
       let mut _2: &T;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff
index 792c77d575b..6d3ad348988 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       debug u => _1;
       let mut _0: Never;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff
index 792c77d575b..6d3ad348988 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       debug u => _1;
       let mut _0: Never;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff
index dd92b8d6d2c..3c9694d0370 100644
--- a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff
@@ -1,45 +1,58 @@
 - // MIR for `unchecked` before LowerIntrinsics
 + // MIR for `unchecked` after LowerIntrinsics
   
-  fn unchecked(_1: i32, _2: i32) -> () {
+  fn unchecked(_1: i32, _2: i32, _3: u32) -> () {
       debug a => _1;
       debug b => _2;
+      debug c => _3;
       let mut _0: ();
-      let _3: i32;
-      let mut _4: i32;
+      let _4: i32;
       let mut _5: i32;
-      let mut _7: i32;
+      let mut _6: i32;
       let mut _8: i32;
-      let mut _10: i32;
+      let mut _9: i32;
       let mut _11: i32;
-      let mut _13: i32;
+      let mut _12: i32;
       let mut _14: i32;
-      let mut _16: i32;
+      let mut _15: i32;
       let mut _17: i32;
-      let mut _19: i32;
+      let mut _18: i32;
       let mut _20: i32;
-      let mut _22: i32;
+      let mut _21: i32;
       let mut _23: i32;
+      let mut _24: i32;
+      let mut _26: i32;
+      let mut _27: u32;
+      let mut _29: i32;
+      let mut _30: u32;
       scope 1 {
-          debug _a => _3;
-          let _6: i32;
+          debug _a => _4;
+          let _7: i32;
           scope 2 {
-              debug _b => _6;
-              let _9: i32;
+              debug _b => _7;
+              let _10: i32;
               scope 3 {
-                  debug _c => _9;
-                  let _12: i32;
+                  debug _c => _10;
+                  let _13: i32;
                   scope 4 {
-                      debug _x => _12;
-                      let _15: i32;
+                      debug _x => _13;
+                      let _16: i32;
                       scope 5 {
-                          debug _y => _15;
-                          let _18: i32;
+                          debug _y => _16;
+                          let _19: i32;
                           scope 6 {
-                              debug _i => _18;
-                              let _21: i32;
+                              debug _i => _19;
+                              let _22: i32;
                               scope 7 {
-                                  debug _j => _21;
+                                  debug _j => _22;
+                                  let _25: i32;
+                                  scope 8 {
+                                      debug _k => _25;
+                                      let _28: i32;
+                                      scope 9 {
+                                          debug _l => _28;
+                                      }
+                                  }
                               }
                           }
                       }
@@ -49,105 +62,133 @@
       }
   
       bb0: {
-          StorageLive(_3);
           StorageLive(_4);
-          _4 = _1;
           StorageLive(_5);
-          _5 = _2;
--         _3 = unchecked_add::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable];
-+         _3 = AddUnchecked(move _4, move _5);
+          _5 = _1;
+          StorageLive(_6);
+          _6 = _2;
+-         _4 = unchecked_add::<i32>(move _5, move _6) -> [return: bb1, unwind unreachable];
++         _4 = AddUnchecked(move _5, move _6);
 +         goto -> bb1;
       }
   
       bb1: {
+          StorageDead(_6);
           StorageDead(_5);
-          StorageDead(_4);
-          StorageLive(_6);
           StorageLive(_7);
-          _7 = _1;
           StorageLive(_8);
-          _8 = _2;
--         _6 = unchecked_sub::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable];
-+         _6 = SubUnchecked(move _7, move _8);
+          _8 = _1;
+          StorageLive(_9);
+          _9 = _2;
+-         _7 = unchecked_sub::<i32>(move _8, move _9) -> [return: bb2, unwind unreachable];
++         _7 = SubUnchecked(move _8, move _9);
 +         goto -> bb2;
       }
   
       bb2: {
+          StorageDead(_9);
           StorageDead(_8);
-          StorageDead(_7);
-          StorageLive(_9);
           StorageLive(_10);
-          _10 = _1;
           StorageLive(_11);
-          _11 = _2;
--         _9 = unchecked_mul::<i32>(move _10, move _11) -> [return: bb3, unwind unreachable];
-+         _9 = MulUnchecked(move _10, move _11);
+          _11 = _1;
+          StorageLive(_12);
+          _12 = _2;
+-         _10 = unchecked_mul::<i32>(move _11, move _12) -> [return: bb3, unwind unreachable];
++         _10 = MulUnchecked(move _11, move _12);
 +         goto -> bb3;
       }
   
       bb3: {
+          StorageDead(_12);
           StorageDead(_11);
-          StorageDead(_10);
-          StorageLive(_12);
           StorageLive(_13);
-          _13 = _1;
           StorageLive(_14);
-          _14 = _2;
--         _12 = unchecked_div::<i32>(move _13, move _14) -> [return: bb4, unwind unreachable];
-+         _12 = Div(move _13, move _14);
+          _14 = _1;
+          StorageLive(_15);
+          _15 = _2;
+-         _13 = unchecked_div::<i32>(move _14, move _15) -> [return: bb4, unwind unreachable];
++         _13 = Div(move _14, move _15);
 +         goto -> bb4;
       }
   
       bb4: {
+          StorageDead(_15);
           StorageDead(_14);
-          StorageDead(_13);
-          StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
           StorageLive(_17);
-          _17 = _2;
--         _15 = unchecked_rem::<i32>(move _16, move _17) -> [return: bb5, unwind unreachable];
-+         _15 = Rem(move _16, move _17);
+          _17 = _1;
+          StorageLive(_18);
+          _18 = _2;
+-         _16 = unchecked_rem::<i32>(move _17, move _18) -> [return: bb5, unwind unreachable];
++         _16 = Rem(move _17, move _18);
 +         goto -> bb5;
       }
   
       bb5: {
+          StorageDead(_18);
           StorageDead(_17);
-          StorageDead(_16);
-          StorageLive(_18);
           StorageLive(_19);
-          _19 = _1;
           StorageLive(_20);
-          _20 = _2;
--         _18 = unchecked_shl::<i32>(move _19, move _20) -> [return: bb6, unwind unreachable];
-+         _18 = ShlUnchecked(move _19, move _20);
+          _20 = _1;
+          StorageLive(_21);
+          _21 = _2;
+-         _19 = unchecked_shl::<i32, i32>(move _20, move _21) -> [return: bb6, unwind unreachable];
++         _19 = ShlUnchecked(move _20, move _21);
 +         goto -> bb6;
       }
   
       bb6: {
+          StorageDead(_21);
           StorageDead(_20);
-          StorageDead(_19);
-          StorageLive(_21);
           StorageLive(_22);
-          _22 = _1;
           StorageLive(_23);
-          _23 = _2;
--         _21 = unchecked_shr::<i32>(move _22, move _23) -> [return: bb7, unwind unreachable];
-+         _21 = ShrUnchecked(move _22, move _23);
+          _23 = _1;
+          StorageLive(_24);
+          _24 = _2;
+-         _22 = unchecked_shr::<i32, i32>(move _23, move _24) -> [return: bb7, unwind unreachable];
++         _22 = ShrUnchecked(move _23, move _24);
 +         goto -> bb7;
       }
   
       bb7: {
+          StorageDead(_24);
           StorageDead(_23);
-          StorageDead(_22);
+          StorageLive(_25);
+          StorageLive(_26);
+          _26 = _1;
+          StorageLive(_27);
+          _27 = _3;
+-         _25 = unchecked_shl::<i32, u32>(move _26, move _27) -> [return: bb8, unwind unreachable];
++         _25 = ShlUnchecked(move _26, move _27);
++         goto -> bb8;
+      }
+  
+      bb8: {
+          StorageDead(_27);
+          StorageDead(_26);
+          StorageLive(_28);
+          StorageLive(_29);
+          _29 = _1;
+          StorageLive(_30);
+          _30 = _3;
+-         _28 = unchecked_shr::<i32, u32>(move _29, move _30) -> [return: bb9, unwind unreachable];
++         _28 = ShrUnchecked(move _29, move _30);
++         goto -> bb9;
+      }
+  
+      bb9: {
+          StorageDead(_30);
+          StorageDead(_29);
           _0 = const ();
-          StorageDead(_21);
-          StorageDead(_18);
-          StorageDead(_15);
-          StorageDead(_12);
-          StorageDead(_9);
-          StorageDead(_6);
-          StorageDead(_3);
+          StorageDead(_28);
+          StorageDead(_25);
+          StorageDead(_22);
+          StorageDead(_19);
+          StorageDead(_16);
+          StorageDead(_13);
+          StorageDead(_10);
+          StorageDead(_7);
+          StorageDead(_4);
           return;
       }
   }
diff --git a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff
index dd92b8d6d2c..3c9694d0370 100644
--- a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff
@@ -1,45 +1,58 @@
 - // MIR for `unchecked` before LowerIntrinsics
 + // MIR for `unchecked` after LowerIntrinsics
   
-  fn unchecked(_1: i32, _2: i32) -> () {
+  fn unchecked(_1: i32, _2: i32, _3: u32) -> () {
       debug a => _1;
       debug b => _2;
+      debug c => _3;
       let mut _0: ();
-      let _3: i32;
-      let mut _4: i32;
+      let _4: i32;
       let mut _5: i32;
-      let mut _7: i32;
+      let mut _6: i32;
       let mut _8: i32;
-      let mut _10: i32;
+      let mut _9: i32;
       let mut _11: i32;
-      let mut _13: i32;
+      let mut _12: i32;
       let mut _14: i32;
-      let mut _16: i32;
+      let mut _15: i32;
       let mut _17: i32;
-      let mut _19: i32;
+      let mut _18: i32;
       let mut _20: i32;
-      let mut _22: i32;
+      let mut _21: i32;
       let mut _23: i32;
+      let mut _24: i32;
+      let mut _26: i32;
+      let mut _27: u32;
+      let mut _29: i32;
+      let mut _30: u32;
       scope 1 {
-          debug _a => _3;
-          let _6: i32;
+          debug _a => _4;
+          let _7: i32;
           scope 2 {
-              debug _b => _6;
-              let _9: i32;
+              debug _b => _7;
+              let _10: i32;
               scope 3 {
-                  debug _c => _9;
-                  let _12: i32;
+                  debug _c => _10;
+                  let _13: i32;
                   scope 4 {
-                      debug _x => _12;
-                      let _15: i32;
+                      debug _x => _13;
+                      let _16: i32;
                       scope 5 {
-                          debug _y => _15;
-                          let _18: i32;
+                          debug _y => _16;
+                          let _19: i32;
                           scope 6 {
-                              debug _i => _18;
-                              let _21: i32;
+                              debug _i => _19;
+                              let _22: i32;
                               scope 7 {
-                                  debug _j => _21;
+                                  debug _j => _22;
+                                  let _25: i32;
+                                  scope 8 {
+                                      debug _k => _25;
+                                      let _28: i32;
+                                      scope 9 {
+                                          debug _l => _28;
+                                      }
+                                  }
                               }
                           }
                       }
@@ -49,105 +62,133 @@
       }
   
       bb0: {
-          StorageLive(_3);
           StorageLive(_4);
-          _4 = _1;
           StorageLive(_5);
-          _5 = _2;
--         _3 = unchecked_add::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable];
-+         _3 = AddUnchecked(move _4, move _5);
+          _5 = _1;
+          StorageLive(_6);
+          _6 = _2;
+-         _4 = unchecked_add::<i32>(move _5, move _6) -> [return: bb1, unwind unreachable];
++         _4 = AddUnchecked(move _5, move _6);
 +         goto -> bb1;
       }
   
       bb1: {
+          StorageDead(_6);
           StorageDead(_5);
-          StorageDead(_4);
-          StorageLive(_6);
           StorageLive(_7);
-          _7 = _1;
           StorageLive(_8);
-          _8 = _2;
--         _6 = unchecked_sub::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable];
-+         _6 = SubUnchecked(move _7, move _8);
+          _8 = _1;
+          StorageLive(_9);
+          _9 = _2;
+-         _7 = unchecked_sub::<i32>(move _8, move _9) -> [return: bb2, unwind unreachable];
++         _7 = SubUnchecked(move _8, move _9);
 +         goto -> bb2;
       }
   
       bb2: {
+          StorageDead(_9);
           StorageDead(_8);
-          StorageDead(_7);
-          StorageLive(_9);
           StorageLive(_10);
-          _10 = _1;
           StorageLive(_11);
-          _11 = _2;
--         _9 = unchecked_mul::<i32>(move _10, move _11) -> [return: bb3, unwind unreachable];
-+         _9 = MulUnchecked(move _10, move _11);
+          _11 = _1;
+          StorageLive(_12);
+          _12 = _2;
+-         _10 = unchecked_mul::<i32>(move _11, move _12) -> [return: bb3, unwind unreachable];
++         _10 = MulUnchecked(move _11, move _12);
 +         goto -> bb3;
       }
   
       bb3: {
+          StorageDead(_12);
           StorageDead(_11);
-          StorageDead(_10);
-          StorageLive(_12);
           StorageLive(_13);
-          _13 = _1;
           StorageLive(_14);
-          _14 = _2;
--         _12 = unchecked_div::<i32>(move _13, move _14) -> [return: bb4, unwind unreachable];
-+         _12 = Div(move _13, move _14);
+          _14 = _1;
+          StorageLive(_15);
+          _15 = _2;
+-         _13 = unchecked_div::<i32>(move _14, move _15) -> [return: bb4, unwind unreachable];
++         _13 = Div(move _14, move _15);
 +         goto -> bb4;
       }
   
       bb4: {
+          StorageDead(_15);
           StorageDead(_14);
-          StorageDead(_13);
-          StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
           StorageLive(_17);
-          _17 = _2;
--         _15 = unchecked_rem::<i32>(move _16, move _17) -> [return: bb5, unwind unreachable];
-+         _15 = Rem(move _16, move _17);
+          _17 = _1;
+          StorageLive(_18);
+          _18 = _2;
+-         _16 = unchecked_rem::<i32>(move _17, move _18) -> [return: bb5, unwind unreachable];
++         _16 = Rem(move _17, move _18);
 +         goto -> bb5;
       }
   
       bb5: {
+          StorageDead(_18);
           StorageDead(_17);
-          StorageDead(_16);
-          StorageLive(_18);
           StorageLive(_19);
-          _19 = _1;
           StorageLive(_20);
-          _20 = _2;
--         _18 = unchecked_shl::<i32>(move _19, move _20) -> [return: bb6, unwind unreachable];
-+         _18 = ShlUnchecked(move _19, move _20);
+          _20 = _1;
+          StorageLive(_21);
+          _21 = _2;
+-         _19 = unchecked_shl::<i32, i32>(move _20, move _21) -> [return: bb6, unwind unreachable];
++         _19 = ShlUnchecked(move _20, move _21);
 +         goto -> bb6;
       }
   
       bb6: {
+          StorageDead(_21);
           StorageDead(_20);
-          StorageDead(_19);
-          StorageLive(_21);
           StorageLive(_22);
-          _22 = _1;
           StorageLive(_23);
-          _23 = _2;
--         _21 = unchecked_shr::<i32>(move _22, move _23) -> [return: bb7, unwind unreachable];
-+         _21 = ShrUnchecked(move _22, move _23);
+          _23 = _1;
+          StorageLive(_24);
+          _24 = _2;
+-         _22 = unchecked_shr::<i32, i32>(move _23, move _24) -> [return: bb7, unwind unreachable];
++         _22 = ShrUnchecked(move _23, move _24);
 +         goto -> bb7;
       }
   
       bb7: {
+          StorageDead(_24);
           StorageDead(_23);
-          StorageDead(_22);
+          StorageLive(_25);
+          StorageLive(_26);
+          _26 = _1;
+          StorageLive(_27);
+          _27 = _3;
+-         _25 = unchecked_shl::<i32, u32>(move _26, move _27) -> [return: bb8, unwind unreachable];
++         _25 = ShlUnchecked(move _26, move _27);
++         goto -> bb8;
+      }
+  
+      bb8: {
+          StorageDead(_27);
+          StorageDead(_26);
+          StorageLive(_28);
+          StorageLive(_29);
+          _29 = _1;
+          StorageLive(_30);
+          _30 = _3;
+-         _28 = unchecked_shr::<i32, u32>(move _29, move _30) -> [return: bb9, unwind unreachable];
++         _28 = ShrUnchecked(move _29, move _30);
++         goto -> bb9;
+      }
+  
+      bb9: {
+          StorageDead(_30);
+          StorageDead(_29);
           _0 = const ();
-          StorageDead(_21);
-          StorageDead(_18);
-          StorageDead(_15);
-          StorageDead(_12);
-          StorageDead(_9);
-          StorageDead(_6);
-          StorageDead(_3);
+          StorageDead(_28);
+          StorageDead(_25);
+          StorageDead(_22);
+          StorageDead(_19);
+          StorageDead(_16);
+          StorageDead(_13);
+          StorageDead(_10);
+          StorageDead(_7);
+          StorageDead(_4);
           return;
       }
   }
diff --git a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-abort.diff
index f5646e7f1e9..2b715ac1d63 100644
--- a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       let mut _0: !;
       let _1: ();
       let mut _2: !;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-unwind.diff
index f5646e7f1e9..2b715ac1d63 100644
--- a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       let mut _0: !;
       let _1: ();
       let mut _2: !;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff
index ddc8cf9a3d9..cc9177c9002 100644
--- a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff
@@ -7,8 +7,6 @@
       let mut _0: ();
       let mut _3: *mut std::string::String;
       let mut _4: std::string::String;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_3);
diff --git a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff
index ddc8cf9a3d9..cc9177c9002 100644
--- a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff
@@ -7,8 +7,6 @@
       let mut _0: ();
       let mut _3: *mut std::string::String;
       let mut _4: std::string::String;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_3);
diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
index 307f7105dd2..ba333ba1a58 100644
--- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
+++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
@@ -60,11 +60,11 @@
       }
   
 -     bb5: {
--         falseEdge -> [real: bb13, imaginary: bb3];
+-         falseEdge -> [real: bb13, imaginary: bb2];
 -     }
 - 
 -     bb6: {
--         falseEdge -> [real: bb8, imaginary: bb5];
+-         falseEdge -> [real: bb8, imaginary: bb1];
 -     }
 - 
 -     bb7: {
@@ -127,7 +127,7 @@
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb1, imaginary: bb5];
+-         falseEdge -> [real: bb1, imaginary: bb1];
 +         goto -> bb1;
       }
   
@@ -184,7 +184,7 @@
           StorageDead(_12);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb2, imaginary: bb3];
+-         falseEdge -> [real: bb2, imaginary: bb2];
 +         goto -> bb2;
       }
   
diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
index 307f7105dd2..ba333ba1a58 100644
--- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
+++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
@@ -60,11 +60,11 @@
       }
   
 -     bb5: {
--         falseEdge -> [real: bb13, imaginary: bb3];
+-         falseEdge -> [real: bb13, imaginary: bb2];
 -     }
 - 
 -     bb6: {
--         falseEdge -> [real: bb8, imaginary: bb5];
+-         falseEdge -> [real: bb8, imaginary: bb1];
 -     }
 - 
 -     bb7: {
@@ -127,7 +127,7 @@
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb1, imaginary: bb5];
+-         falseEdge -> [real: bb1, imaginary: bb1];
 +         goto -> bb1;
       }
   
@@ -184,7 +184,7 @@
           StorageDead(_12);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb2, imaginary: bb3];
+-         falseEdge -> [real: bb2, imaginary: bb2];
 +         goto -> bb2;
       }
   
diff --git a/tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir b/tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir
deleted file mode 100644
index 107f56f7f69..00000000000
--- a/tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir
+++ /dev/null
@@ -1,106 +0,0 @@
-// MIR for `main` after SimplifyCfg-initial
-
-fn main() -> () {
-    let mut _0: ();
-    let _1: i32;
-    let _3: i32;
-    let mut _4: bool;
-    let mut _5: bool;
-    let mut _6: bool;
-    let mut _7: bool;
-    let mut _8: &i32;
-    let mut _9: bool;
-    scope 1 {
-        debug x => _1;
-        let _2: bool;
-        scope 2 {
-            debug b => _2;
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);
-        _1 = const 3_i32;
-        FakeRead(ForLet(None), _1);
-        StorageLive(_2);
-        _2 = const true;
-        FakeRead(ForLet(None), _2);
-        StorageLive(_3);
-        PlaceMention(_1);
-        _6 = Le(const 0_i32, _1);
-        switchInt(move _6) -> [0: bb3, otherwise: bb8];
-    }
-
-    bb1: {
-        _3 = const 3_i32;
-        goto -> bb14;
-    }
-
-    bb2: {
-        falseEdge -> [real: bb9, imaginary: bb4];
-    }
-
-    bb3: {
-        _4 = Le(const 10_i32, _1);
-        switchInt(move _4) -> [0: bb5, otherwise: bb7];
-    }
-
-    bb4: {
-        falseEdge -> [real: bb12, imaginary: bb6];
-    }
-
-    bb5: {
-        switchInt(_1) -> [4294967295: bb6, otherwise: bb1];
-    }
-
-    bb6: {
-        falseEdge -> [real: bb13, imaginary: bb1];
-    }
-
-    bb7: {
-        _5 = Le(_1, const 20_i32);
-        switchInt(move _5) -> [0: bb5, otherwise: bb4];
-    }
-
-    bb8: {
-        _7 = Lt(_1, const 10_i32);
-        switchInt(move _7) -> [0: bb3, otherwise: bb2];
-    }
-
-    bb9: {
-        _8 = &fake _1;
-        StorageLive(_9);
-        _9 = _2;
-        switchInt(move _9) -> [0: bb11, otherwise: bb10];
-    }
-
-    bb10: {
-        StorageDead(_9);
-        FakeRead(ForMatchGuard, _8);
-        _3 = const 0_i32;
-        goto -> bb14;
-    }
-
-    bb11: {
-        StorageDead(_9);
-        falseEdge -> [real: bb1, imaginary: bb4];
-    }
-
-    bb12: {
-        _3 = const 1_i32;
-        goto -> bb14;
-    }
-
-    bb13: {
-        _3 = const 2_i32;
-        goto -> bb14;
-    }
-
-    bb14: {
-        StorageDead(_3);
-        _0 = const ();
-        StorageDead(_2);
-        StorageDead(_1);
-        return;
-    }
-}
diff --git a/tests/mir-opt/match_test.rs b/tests/mir-opt/match_test.rs
deleted file mode 100644
index e465289e427..00000000000
--- a/tests/mir-opt/match_test.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// skip-filecheck
-// Make sure redundant testing paths in `match` expressions are sorted out.
-
-#![feature(exclusive_range_pattern)]
-
-// EMIT_MIR match_test.main.SimplifyCfg-initial.after.mir
-fn main() {
-    let x = 3;
-    let b = true;
-
-    // When `(0..=10).contains(x) && !b`, we should jump to the last arm
-    // without testing two other candidates.
-    match x {
-        0..10 if b => 0,
-        10..=20 => 1,
-        -1 => 2,
-        _ => 3,
-    };
-}
diff --git a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir
index 656934fce42..845673601b2 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir
@@ -21,13 +21,9 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> {
                 debug self => _1;
                 debug rhs => _2;
                 let mut _3: u32;
-                scope 5 {
-                    scope 6 (inlined core::num::<impl u32>::unchecked_shl) {
-                        debug self => _1;
-                        debug rhs => _3;
-                        scope 7 {
-                        }
-                    }
+                scope 5 (inlined core::num::<impl u32>::unchecked_shl) {
+                    debug self => _1;
+                    debug rhs => _3;
                 }
             }
         }
diff --git a/tests/mir-opt/pre-codegen/derived_ord.rs b/tests/mir-opt/pre-codegen/derived_ord.rs
new file mode 100644
index 00000000000..bad751edf84
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/derived_ord.rs
@@ -0,0 +1,9 @@
+// skip-filecheck
+//@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=0
+
+#![crate_type = "lib"]
+
+#[derive(PartialOrd, PartialEq)]
+pub struct MultiField(char, i16);
+
+// EMIT_MIR derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
diff --git a/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
new file mode 100644
index 00000000000..a6c64425912
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
@@ -0,0 +1,78 @@
+// MIR for `<impl at $DIR/derived_ord.rs:6:10: 6:20>::partial_cmp` after PreCodegen
+
+fn <impl at $DIR/derived_ord.rs:6:10: 6:20>::partial_cmp(_1: &MultiField, _2: &MultiField) -> Option<std::cmp::Ordering> {
+    debug self => _1;
+    debug other => _2;
+    let mut _0: std::option::Option<std::cmp::Ordering>;
+    let mut _3: &char;
+    let mut _4: &char;
+    let mut _8: std::option::Option<std::cmp::Ordering>;
+    let mut _9: i8;
+    let mut _10: &i16;
+    let mut _11: &i16;
+    scope 1 {
+        debug cmp => _8;
+    }
+    scope 2 (inlined std::cmp::impls::<impl PartialOrd for char>::partial_cmp) {
+        debug self => _3;
+        debug other => _4;
+        let mut _5: char;
+        let mut _6: char;
+        let mut _7: std::cmp::Ordering;
+    }
+    scope 3 (inlined std::cmp::impls::<impl PartialOrd for i16>::partial_cmp) {
+        debug self => _10;
+        debug other => _11;
+        let mut _12: i16;
+        let mut _13: i16;
+        let mut _14: std::cmp::Ordering;
+    }
+
+    bb0: {
+        StorageLive(_3);
+        _3 = &((*_1).0: char);
+        StorageLive(_4);
+        _4 = &((*_2).0: char);
+        StorageLive(_5);
+        _5 = ((*_1).0: char);
+        StorageLive(_6);
+        _6 = ((*_2).0: char);
+        _7 = Cmp(move _5, move _6);
+        StorageDead(_6);
+        StorageDead(_5);
+        _8 = Option::<std::cmp::Ordering>::Some(_7);
+        StorageDead(_4);
+        StorageDead(_3);
+        _9 = discriminant(_7);
+        switchInt(move _9) -> [0: bb1, otherwise: bb2];
+    }
+
+    bb1: {
+        StorageLive(_10);
+        _10 = &((*_1).1: i16);
+        StorageLive(_11);
+        _11 = &((*_2).1: i16);
+        StorageLive(_14);
+        StorageLive(_12);
+        _12 = ((*_1).1: i16);
+        StorageLive(_13);
+        _13 = ((*_2).1: i16);
+        _14 = Cmp(move _12, move _13);
+        StorageDead(_13);
+        StorageDead(_12);
+        _0 = Option::<std::cmp::Ordering>::Some(move _14);
+        StorageDead(_14);
+        StorageDead(_11);
+        StorageDead(_10);
+        goto -> bb3;
+    }
+
+    bb2: {
+        _0 = _8;
+        goto -> bb3;
+    }
+
+    bb3: {
+        return;
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
index ebe846e8a51..518fedffc16 100644
--- a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
@@ -5,10 +5,8 @@ fn ub_if_b(_1: Thing) -> Thing {
     let mut _0: Thing;
     let mut _2: isize;
     scope 1 (inlined unreachable_unchecked) {
-        scope 2 {
-        }
-        scope 3 (inlined core::ub_checks::check_language_ub) {
-            scope 4 (inlined core::ub_checks::check_language_ub::runtime) {
+        scope 2 (inlined core::ub_checks::check_language_ub) {
+            scope 3 (inlined core::ub_checks::check_language_ub::runtime) {
             }
         }
     }
diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
index 0b5ed6ee169..cdb7eea74fb 100644
--- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
@@ -26,10 +26,8 @@ fn int_range(_1: usize, _2: usize) -> () {
                 let mut _12: usize;
                 scope 6 {
                     debug old => _11;
-                    scope 7 {
-                    }
                 }
-                scope 8 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
+                scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
                     debug self => _6;
                     debug other => _7;
                     let mut _8: usize;
diff --git a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-abort.mir
index 26919dd98dd..c744787fce2 100644
--- a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-abort.mir
@@ -8,21 +8,15 @@ fn mem_replace(_1: &mut u32, _2: u32) -> u32 {
         debug dest => _1;
         debug src => _2;
         scope 2 {
-            scope 3 {
-                debug result => _0;
-                scope 6 (inlined std::ptr::write::<u32>) {
-                    debug dst => _1;
-                    debug src => _2;
-                    scope 7 {
-                    }
-                }
-            }
-            scope 4 (inlined std::ptr::read::<u32>) {
-                debug src => _1;
-                scope 5 {
-                }
+            debug result => _0;
+            scope 4 (inlined std::ptr::write::<u32>) {
+                debug dst => _1;
+                debug src => _2;
             }
         }
+        scope 3 (inlined std::ptr::read::<u32>) {
+            debug src => _1;
+        }
     }
 
     bb0: {
diff --git a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-unwind.mir
index 26919dd98dd..c744787fce2 100644
--- a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-unwind.mir
@@ -8,21 +8,15 @@ fn mem_replace(_1: &mut u32, _2: u32) -> u32 {
         debug dest => _1;
         debug src => _2;
         scope 2 {
-            scope 3 {
-                debug result => _0;
-                scope 6 (inlined std::ptr::write::<u32>) {
-                    debug dst => _1;
-                    debug src => _2;
-                    scope 7 {
-                    }
-                }
-            }
-            scope 4 (inlined std::ptr::read::<u32>) {
-                debug src => _1;
-                scope 5 {
-                }
+            debug result => _0;
+            scope 4 (inlined std::ptr::write::<u32>) {
+                debug dst => _1;
+                debug src => _2;
             }
         }
+        scope 3 (inlined std::ptr::read::<u32>) {
+            debug src => _1;
+        }
     }
 
     bb0: {
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
index ed965770adb..002d55ad9d9 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
@@ -29,10 +29,8 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
                 let mut _13: u32;
                 scope 6 {
                     debug old => _12;
-                    scope 7 {
-                    }
                 }
-                scope 8 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
+                scope 7 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
                     debug self => _7;
                     debug other => _8;
                     let mut _9: u32;
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
index a7ee9be19bd..d5021ac84d2 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
@@ -29,10 +29,8 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
                 let mut _13: u32;
                 scope 6 {
                     debug old => _12;
-                    scope 7 {
-                    }
                 }
-                scope 8 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
+                scope 7 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
                     debug self => _7;
                     debug other => _8;
                     let mut _9: u32;
diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
index f674f6a3009..7faae1d863c 100644
--- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
@@ -14,10 +14,8 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> {
             let mut _8: u32;
             scope 3 {
                 debug old => _7;
-                scope 4 {
-                }
             }
-            scope 5 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
+            scope 4 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
                 debug self => _2;
                 debug other => _3;
                 let mut _4: u32;
diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
index a5029dcad3a..37f00533b60 100644
--- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
@@ -14,10 +14,8 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> {
             let mut _8: u32;
             scope 3 {
                 debug old => _7;
-                scope 4 {
-                }
             }
-            scope 5 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
+            scope 4 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
                 debug self => _2;
                 debug other => _3;
                 let mut _4: u32;
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
index bcc540ae6fc..e5490955a36 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
@@ -9,8 +9,6 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
         debug index => _2;
         let mut _3: *mut [u32];
         let mut _4: *mut [u32];
-        scope 2 {
-        }
     }
 
     bb0: {
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
index 1fe7da7d2fd..810fee9a149 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
@@ -9,8 +9,6 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
         debug index => _2;
         let mut _3: *mut [u32];
         let mut _4: *mut [u32];
-        scope 2 {
-        }
     }
 
     bb0: {
diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir
index f698e15d302..1ec85906385 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir
@@ -37,52 +37,42 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
         debug self => _13;
-        scope 20 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
+        scope 15 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
             debug iter => _13;
         }
     }
-    scope 21 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
+    scope 16 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
         debug self => _14;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
index eae9f5909e6..70cdf3f41c2 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
@@ -37,52 +37,42 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
         debug self => _13;
-        scope 20 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
+        scope 15 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
             debug iter => _13;
         }
     }
-    scope 21 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
+    scope 16 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
         debug self => _14;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir
index 158ae0de890..d8252e7267a 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir
@@ -34,46 +34,36 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
         debug self => _13;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
index ac9e31a0da8..b3904dc70a6 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
@@ -34,46 +34,36 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
         debug self => _13;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
index 543e8918e39..5ab88c9b855 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
@@ -35,10 +35,8 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
                 let mut _13: usize;
                 scope 7 {
                     debug old => _12;
-                    scope 8 {
-                    }
                 }
-                scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
+                scope 8 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
                     debug self => _7;
                     debug other => _8;
                     let mut _9: usize;
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
index a16e9cd9e51..513651090a8 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
@@ -35,10 +35,8 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
                 let mut _13: usize;
                 scope 7 {
                     debug old => _12;
-                    scope 8 {
-                    }
                 }
-                scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
+                scope 8 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
                     debug self => _7;
                     debug other => _8;
                     let mut _9: usize;
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
index 9550df012f8..091c8a0e968 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
@@ -19,7 +19,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
         scope 2 {
             debug x => _20;
         }
-        scope 22 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
+        scope 17 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
             debug self => _16;
             let mut _17: &mut std::slice::Iter<'_, T>;
         }
@@ -39,52 +39,42 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
         debug self => _13;
-        scope 20 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
+        scope 15 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
             debug iter => _13;
         }
     }
-    scope 21 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
+    scope 16 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
         debug self => _14;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
index d75aabd12fc..1873d452f34 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
@@ -19,7 +19,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
         scope 2 {
             debug x => _20;
         }
-        scope 22 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
+        scope 17 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
             debug self => _16;
             let mut _17: &mut std::slice::Iter<'_, T>;
         }
@@ -39,52 +39,42 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
         debug self => _13;
-        scope 20 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
+        scope 15 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
             debug iter => _13;
         }
     }
-    scope 21 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
+    scope 16 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
         debug self => _14;
     }
 
diff --git a/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff
index 747028e128f..859097d3966 100644
--- a/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff
@@ -25,8 +25,6 @@
                       let _7: i32;
                       scope 5 {
                           debug a => _7;
-                          scope 6 {
-                          }
                       }
                   }
               }
diff --git a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
index ce5ddbfdd12..1e6a168f756 100644
--- a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
@@ -6,218 +6,196 @@
       debug multiple => _2;
       let mut _0: ();
       let _3: ();
+      let _4: usize;
       let _7: ();
       let mut _8: ();
       let _9: ();
+      let _10: usize;
       let mut _13: *const usize;
       let _15: ();
       let mut _16: ();
       let _17: ();
+      let _18: usize;
       let _22: ();
       let mut _23: &*const usize;
       let _24: ();
+      let _25: usize;
       let _29: ();
       let mut _30: *mut *const usize;
       let _31: ();
+      let _32: usize;
       let _35: ();
       let mut _36: *const usize;
       let _37: ();
+      let _38: usize;
       let _44: ();
       let mut _45: *const usize;
       let _46: ();
+      let _47: *const T;
       let _49: ();
       let mut _50: ();
       let _51: ();
+      let _52: *const T;
       let mut _53: *const T;
       let _55: ();
       let mut _56: ();
       let _57: ();
+      let _58: usize;
       let _62: ();
       let mut _63: ();
       let _64: ();
+      let _65: usize;
       let _69: ();
       let mut _70: ();
+      let _71: usize;
       let _75: ();
       let mut _76: ();
       scope 1 {
-          let _4: usize;
+          debug a => _4;
+          let _5: *const usize;
           scope 2 {
-              debug a => _4;
-              let _5: *const usize;
+              debug b => _5;
+              let _6: usize;
               scope 3 {
-                  debug b => _5;
-                  let _6: usize;
-                  scope 4 {
-                      debug c => _6;
-                  }
+                  debug c => _6;
               }
           }
       }
-      scope 5 {
-          let _10: usize;
-          scope 6 {
-              debug a => _10;
-              let _11: usize;
-              scope 7 {
-                  debug a2 => _11;
-                  let mut _12: *const usize;
-                  scope 8 {
-                      debug b => _12;
-                      let _14: usize;
-                      scope 9 {
-                          debug c => _14;
-                      }
+      scope 4 {
+          debug a => _10;
+          let _11: usize;
+          scope 5 {
+              debug a2 => _11;
+              let mut _12: *const usize;
+              scope 6 {
+                  debug b => _12;
+                  let _14: usize;
+                  scope 7 {
+                      debug c => _14;
                   }
               }
           }
       }
-      scope 10 {
-          let _18: usize;
-          scope 11 {
-              debug a => _18;
-              let _19: *const usize;
-              scope 12 {
-                  debug b => _19;
-                  let _20: &*const usize;
-                  scope 13 {
-                      debug d => _20;
-                      let _21: usize;
-                      scope 14 {
-                          debug c => _21;
-                      }
+      scope 8 {
+          debug a => _18;
+          let _19: *const usize;
+          scope 9 {
+              debug b => _19;
+              let _20: &*const usize;
+              scope 10 {
+                  debug d => _20;
+                  let _21: usize;
+                  scope 11 {
+                      debug c => _21;
                   }
               }
           }
       }
-      scope 15 {
-          let _25: usize;
-          scope 16 {
-              debug a => _25;
-              let mut _26: *const usize;
-              scope 17 {
-                  debug b => _26;
-                  let _27: *mut *const usize;
-                  scope 18 {
-                      debug d => _27;
-                      let _28: usize;
-                      scope 19 {
-                          debug c => _28;
-                      }
+      scope 12 {
+          debug a => _25;
+          let mut _26: *const usize;
+          scope 13 {
+              debug b => _26;
+              let _27: *mut *const usize;
+              scope 14 {
+                  debug d => _27;
+                  let _28: usize;
+                  scope 15 {
+                      debug c => _28;
                   }
               }
           }
       }
-      scope 20 {
-          let _32: usize;
-          scope 21 {
-              debug a => _32;
-              let _33: *const usize;
-              scope 22 {
-                  debug b => _33;
-                  let _34: usize;
-                  scope 23 {
-                      debug c => _34;
-                  }
+      scope 16 {
+          debug a => _32;
+          let _33: *const usize;
+          scope 17 {
+              debug b => _33;
+              let _34: usize;
+              scope 18 {
+                  debug c => _34;
               }
           }
       }
-      scope 24 {
-          let _38: usize;
-          scope 25 {
-              debug a => _38;
-              let _39: *const usize;
-              scope 26 {
-                  debug b1 => _39;
-                  let _40: usize;
-                  scope 27 {
-                      debug c => _40;
-                      let _41: *const usize;
-                      scope 28 {
-                          debug b2 => _41;
-                          let _42: usize;
-                          scope 29 {
-                              debug c2 => _42;
-                              let _43: *const usize;
-                              scope 30 {
-                                  debug b3 => _43;
-                              }
+      scope 19 {
+          debug a => _38;
+          let _39: *const usize;
+          scope 20 {
+              debug b1 => _39;
+              let _40: usize;
+              scope 21 {
+                  debug c => _40;
+                  let _41: *const usize;
+                  scope 22 {
+                      debug b2 => _41;
+                      let _42: usize;
+                      scope 23 {
+                          debug c2 => _42;
+                          let _43: *const usize;
+                          scope 24 {
+                              debug b3 => _43;
                           }
                       }
                   }
               }
           }
       }
-      scope 31 {
-          let _47: *const T;
-          scope 32 {
--             debug a => _47;
-+             debug a => _1;
-              let _48: T;
-              scope 33 {
-                  debug b => _48;
-              }
+      scope 25 {
+-         debug a => _47;
++         debug a => _1;
+          let _48: T;
+          scope 26 {
+              debug b => _48;
           }
       }
-      scope 34 {
-          let _52: *const T;
-          scope 35 {
-              debug a => _52;
-              let _54: T;
-              scope 36 {
-                  debug b => _54;
-              }
+      scope 27 {
+          debug a => _52;
+          let _54: T;
+          scope 28 {
+              debug b => _54;
           }
       }
-      scope 37 {
-          let _58: usize;
-          scope 38 {
-              debug a => _58;
-              let _59: *const usize;
-              scope 39 {
-                  debug b => _59;
-                  let _60: *const usize;
-                  scope 40 {
-                      debug c => _60;
-                      let _61: usize;
-                      scope 41 {
-                          debug e => _61;
-                      }
+      scope 29 {
+          debug a => _58;
+          let _59: *const usize;
+          scope 30 {
+              debug b => _59;
+              let _60: *const usize;
+              scope 31 {
+                  debug c => _60;
+                  let _61: usize;
+                  scope 32 {
+                      debug e => _61;
                   }
               }
           }
       }
-      scope 42 {
-          let _65: usize;
-          scope 43 {
-              debug a => _65;
-              let _66: *const usize;
-              scope 44 {
-                  debug b => _66;
-                  let _67: &*const usize;
-                  scope 45 {
-                      debug d => _67;
-                      let _68: usize;
-                      scope 46 {
-                          debug c => _68;
-                      }
+      scope 33 {
+          debug a => _65;
+          let _66: *const usize;
+          scope 34 {
+              debug b => _66;
+              let _67: &*const usize;
+              scope 35 {
+                  debug d => _67;
+                  let _68: usize;
+                  scope 36 {
+                      debug c => _68;
                   }
               }
           }
       }
-      scope 47 {
-          let _71: usize;
-          scope 48 {
-              debug a => _71;
-              let mut _72: *const usize;
-              scope 49 {
-                  debug b => _72;
-                  let _73: &mut *const usize;
-                  scope 50 {
-                      debug d => _73;
-                      let _74: usize;
-                      scope 51 {
-                          debug c => _74;
-                      }
+      scope 37 {
+          debug a => _71;
+          let mut _72: *const usize;
+          scope 38 {
+              debug b => _72;
+              let _73: &mut *const usize;
+              scope 39 {
+                  debug d => _73;
+                  let _74: usize;
+                  scope 40 {
+                      debug c => _74;
                   }
               }
           }
diff --git a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff
index b6b2acc0b43..5629d04f1b1 100644
--- a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff
@@ -6,197 +6,177 @@
       debug multiple => _2;
       let mut _0: ();
       let _3: ();
+      let mut _4: usize;
       let _7: ();
       let mut _8: ();
       let _9: ();
+      let mut _10: usize;
       let mut _13: *mut usize;
       let _15: ();
       let mut _16: ();
       let _17: ();
+      let mut _18: usize;
       let _22: ();
       let mut _23: &*mut usize;
       let _24: ();
+      let mut _25: usize;
       let _29: ();
       let mut _30: *mut *mut usize;
       let _31: ();
+      let mut _32: usize;
       let _35: ();
       let mut _36: *mut usize;
       let _37: ();
+      let mut _38: usize;
       let _44: ();
       let mut _45: *mut usize;
       let _46: ();
+      let _47: *mut T;
       let _49: ();
       let mut _50: ();
       let _51: ();
+      let _52: *mut T;
       let mut _53: *mut T;
       let _55: ();
       let mut _56: ();
       let _57: ();
+      let mut _58: usize;
       let _62: ();
       let mut _63: ();
+      let mut _64: usize;
       let _68: ();
       let mut _69: ();
       scope 1 {
-          let mut _4: usize;
+          debug a => _4;
+          let _5: *mut usize;
           scope 2 {
-              debug a => _4;
-              let _5: *mut usize;
+              debug b => _5;
+              let _6: usize;
               scope 3 {
-                  debug b => _5;
-                  let _6: usize;
-                  scope 4 {
-                      debug c => _6;
-                  }
+                  debug c => _6;
               }
           }
       }
-      scope 5 {
-          let mut _10: usize;
-          scope 6 {
-              debug a => _10;
-              let mut _11: usize;
-              scope 7 {
-                  debug a2 => _11;
-                  let mut _12: *mut usize;
-                  scope 8 {
-                      debug b => _12;
-                      let _14: usize;
-                      scope 9 {
-                          debug c => _14;
-                      }
+      scope 4 {
+          debug a => _10;
+          let mut _11: usize;
+          scope 5 {
+              debug a2 => _11;
+              let mut _12: *mut usize;
+              scope 6 {
+                  debug b => _12;
+                  let _14: usize;
+                  scope 7 {
+                      debug c => _14;
                   }
               }
           }
       }
-      scope 10 {
-          let mut _18: usize;
-          scope 11 {
-              debug a => _18;
-              let _19: *mut usize;
-              scope 12 {
-                  debug b => _19;
-                  let _20: &*mut usize;
-                  scope 13 {
-                      debug d => _20;
-                      let _21: usize;
-                      scope 14 {
-                          debug c => _21;
-                      }
+      scope 8 {
+          debug a => _18;
+          let _19: *mut usize;
+          scope 9 {
+              debug b => _19;
+              let _20: &*mut usize;
+              scope 10 {
+                  debug d => _20;
+                  let _21: usize;
+                  scope 11 {
+                      debug c => _21;
                   }
               }
           }
       }
-      scope 15 {
-          let mut _25: usize;
-          scope 16 {
-              debug a => _25;
-              let mut _26: *mut usize;
-              scope 17 {
-                  debug b => _26;
-                  let _27: *mut *mut usize;
-                  scope 18 {
-                      debug d => _27;
-                      let _28: usize;
-                      scope 19 {
-                          debug c => _28;
-                      }
+      scope 12 {
+          debug a => _25;
+          let mut _26: *mut usize;
+          scope 13 {
+              debug b => _26;
+              let _27: *mut *mut usize;
+              scope 14 {
+                  debug d => _27;
+                  let _28: usize;
+                  scope 15 {
+                      debug c => _28;
                   }
               }
           }
       }
-      scope 20 {
-          let mut _32: usize;
-          scope 21 {
-              debug a => _32;
-              let _33: *mut usize;
-              scope 22 {
-                  debug b => _33;
-                  let _34: usize;
-                  scope 23 {
-                      debug c => _34;
-                  }
+      scope 16 {
+          debug a => _32;
+          let _33: *mut usize;
+          scope 17 {
+              debug b => _33;
+              let _34: usize;
+              scope 18 {
+                  debug c => _34;
               }
           }
       }
-      scope 24 {
-          let mut _38: usize;
-          scope 25 {
-              debug a => _38;
-              let _39: *mut usize;
-              scope 26 {
-                  debug b1 => _39;
-                  let _40: usize;
-                  scope 27 {
-                      debug c => _40;
-                      let _41: *mut usize;
-                      scope 28 {
-                          debug b2 => _41;
-                          let _42: usize;
-                          scope 29 {
-                              debug c2 => _42;
-                              let _43: *mut usize;
-                              scope 30 {
-                                  debug b3 => _43;
-                              }
+      scope 19 {
+          debug a => _38;
+          let _39: *mut usize;
+          scope 20 {
+              debug b1 => _39;
+              let _40: usize;
+              scope 21 {
+                  debug c => _40;
+                  let _41: *mut usize;
+                  scope 22 {
+                      debug b2 => _41;
+                      let _42: usize;
+                      scope 23 {
+                          debug c2 => _42;
+                          let _43: *mut usize;
+                          scope 24 {
+                              debug b3 => _43;
                           }
                       }
                   }
               }
           }
       }
-      scope 31 {
-          let _47: *mut T;
-          scope 32 {
--             debug a => _47;
-+             debug a => _1;
-              let _48: T;
-              scope 33 {
-                  debug b => _48;
-              }
+      scope 25 {
+-         debug a => _47;
++         debug a => _1;
+          let _48: T;
+          scope 26 {
+              debug b => _48;
           }
       }
-      scope 34 {
-          let _52: *mut T;
-          scope 35 {
-              debug a => _52;
-              let _54: T;
-              scope 36 {
-                  debug b => _54;
-              }
+      scope 27 {
+          debug a => _52;
+          let _54: T;
+          scope 28 {
+              debug b => _54;
           }
       }
-      scope 37 {
-          let mut _58: usize;
-          scope 38 {
-              debug a => _58;
-              let _59: *mut usize;
-              scope 39 {
-                  debug b => _59;
-                  let _60: &*mut usize;
-                  scope 40 {
-                      debug d => _60;
-                      let _61: usize;
-                      scope 41 {
-                          debug c => _61;
-                      }
+      scope 29 {
+          debug a => _58;
+          let _59: *mut usize;
+          scope 30 {
+              debug b => _59;
+              let _60: &*mut usize;
+              scope 31 {
+                  debug d => _60;
+                  let _61: usize;
+                  scope 32 {
+                      debug c => _61;
                   }
               }
           }
       }
-      scope 42 {
-          let mut _64: usize;
-          scope 43 {
-              debug a => _64;
-              let mut _65: *mut usize;
-              scope 44 {
-                  debug b => _65;
-                  let _66: &mut *mut usize;
-                  scope 45 {
-                      debug d => _66;
-                      let _67: usize;
-                      scope 46 {
-                          debug c => _67;
-                      }
+      scope 33 {
+          debug a => _64;
+          let mut _65: *mut usize;
+          scope 34 {
+              debug b => _65;
+              let _66: &mut *mut usize;
+              scope 35 {
+                  debug d => _66;
+                  let _67: usize;
+                  scope 36 {
+                      debug c => _67;
                   }
               }
           }
diff --git a/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff b/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff
index b4912a918ba..a5427cea1f8 100644
--- a/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff
@@ -12,16 +12,12 @@
       scope 1 {
 -         debug y => _1;
 +         debug y => _3;
-          scope 5 {
-          }
       }
       scope 2 {
           debug a => _2;
           let _3: *mut i32;
           scope 3 {
               debug x => _3;
-              scope 4 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-abort.mir
index 7124b4c1cd8..f9d58ea60a3 100644
--- a/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-abort.mir
+++ b/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-abort.mir
@@ -36,22 +36,18 @@ fn array_casts() -> () {
             debug p => _2;
             let _8: [usize; 2];
             scope 3 {
-            }
-            scope 4 {
                 debug x => _8;
                 let _9: *const usize;
-                scope 5 {
+                scope 4 {
                     debug p => _9;
                     let _20: &usize;
                     let _21: &usize;
                     let mut _34: &usize;
-                    scope 6 {
-                    }
-                    scope 7 {
+                    scope 5 {
                         debug left_val => _20;
                         debug right_val => _21;
                         let _26: core::panicking::AssertKind;
-                        scope 8 {
+                        scope 6 {
                             debug kind => _26;
                         }
                     }
diff --git a/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
index be04757f2a3..b0b70cd5d91 100644
--- a/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
+++ b/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
@@ -36,22 +36,18 @@ fn array_casts() -> () {
             debug p => _2;
             let _8: [usize; 2];
             scope 3 {
-            }
-            scope 4 {
                 debug x => _8;
                 let _9: *const usize;
-                scope 5 {
+                scope 4 {
                     debug p => _9;
                     let _20: &usize;
                     let _21: &usize;
                     let mut _34: &usize;
-                    scope 6 {
-                    }
-                    scope 7 {
+                    scope 5 {
                         debug left_val => _20;
                         debug right_val => _21;
                         let _26: core::panicking::AssertKind;
-                        scope 8 {
+                        scope 6 {
                             debug kind => _26;
                         }
                     }
diff --git a/tests/mir-opt/simplify_dead_blocks.assert_nonzero_nonmax.SimplifyCfg-after-unreachable-enum-branching.diff b/tests/mir-opt/simplify_dead_blocks.assert_nonzero_nonmax.SimplifyCfg-after-unreachable-enum-branching.diff
new file mode 100644
index 00000000000..4400cfaef81
--- /dev/null
+++ b/tests/mir-opt/simplify_dead_blocks.assert_nonzero_nonmax.SimplifyCfg-after-unreachable-enum-branching.diff
@@ -0,0 +1,33 @@
+- // MIR for `assert_nonzero_nonmax` before SimplifyCfg-after-unreachable-enum-branching
++ // MIR for `assert_nonzero_nonmax` after SimplifyCfg-after-unreachable-enum-branching
+  
+  fn assert_nonzero_nonmax(_1: u8) -> u8 {
+      let mut _0: u8;
+  
+      bb0: {
+-         switchInt(_1) -> [0: bb3, 1: bb2, 255: bb3, otherwise: bb4];
++         switchInt(_1) -> [0: bb2, 1: bb1, 255: bb2, otherwise: bb3];
+      }
+  
+      bb1: {
+-         _0 = const 1_u8;
+-         return;
+-     }
+- 
+-     bb2: {
+          _0 = const 2_u8;
+          return;
+      }
+  
+-     bb3: {
++     bb2: {
+          unreachable;
+      }
+  
+-     bb4: {
++     bb3: {
+          _0 = _1;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/simplify_dead_blocks.rs b/tests/mir-opt/simplify_dead_blocks.rs
new file mode 100644
index 00000000000..d4de85622d4
--- /dev/null
+++ b/tests/mir-opt/simplify_dead_blocks.rs
@@ -0,0 +1,52 @@
+//@ unit-test: SimplifyCfg-after-unreachable-enum-branching
+#![feature(custom_mir, core_intrinsics)]
+#![crate_type = "lib"]
+
+use std::intrinsics::mir::*;
+
+// Check that we correctly cleaned up the dead BB.
+// EMIT_MIR simplify_dead_blocks.assert_nonzero_nonmax.SimplifyCfg-after-unreachable-enum-branching.diff
+#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
+pub unsafe fn assert_nonzero_nonmax(x: u8) -> u8 {
+    // CHECK-LABEL: fn assert_nonzero_nonmax(
+    // CHECK: bb0: {
+    // CHECK-NEXT: switchInt({{.*}}) -> [0: [[unreachable:bb.*]], 1: [[retblock2:bb.*]], 255: [[unreachable:bb.*]], otherwise: [[retblock:bb.*]]];
+    // CHECK-NEXT: }
+    // CHECK-NOT: _0 = const 1_u8;
+    // CHECK: [[retblock2]]: {
+    // CHECK-NEXT: _0 = const 2_u8;
+    // CHECK-NEXT: return;
+    // CHECK-NEXT: }
+    // CHECK: [[unreachable]]: {
+    // CHECK-NEXT: unreachable;
+    // CHECK-NEXT: }
+    // CHECK: [[retblock]]: {
+    // CHECK-NEXT: _0 = _1;
+    // CHECK-NEXT: return;
+    // CHECK-NEXT: }
+    mir!(
+        {
+            match x {
+                0 => unreachable,
+                1 => retblock2,
+                u8::MAX => unreachable,
+                _ => retblock,
+            }
+        }
+        deadRetblock1 = {
+            RET = 1;
+            Return()
+        }
+        retblock2 = {
+            RET = 2;
+            Return()
+        }
+        unreachable = {
+            Unreachable()
+        }
+        retblock = {
+            RET = x;
+            Return()
+        }
+    )
+}
diff --git a/tests/mir-opt/simplify_duplicate_unreachable_blocks.assert_nonzero_nonmax.SimplifyCfg-after-uninhabited-enum-branching.diff b/tests/mir-opt/simplify_duplicate_unreachable_blocks.assert_nonzero_nonmax.SimplifyCfg-after-uninhabited-enum-branching.diff
deleted file mode 100644
index 35c0a4d45df..00000000000
--- a/tests/mir-opt/simplify_duplicate_unreachable_blocks.assert_nonzero_nonmax.SimplifyCfg-after-uninhabited-enum-branching.diff
+++ /dev/null
@@ -1,25 +0,0 @@
-- // MIR for `assert_nonzero_nonmax` before SimplifyCfg-after-uninhabited-enum-branching
-+ // MIR for `assert_nonzero_nonmax` after SimplifyCfg-after-uninhabited-enum-branching
-  
-  fn assert_nonzero_nonmax(_1: u8) -> u8 {
-      let mut _0: u8;
-  
-      bb0: {
--         switchInt(_1) -> [0: bb1, 255: bb2, otherwise: bb3];
-+         switchInt(_1) -> [0: bb1, 255: bb1, otherwise: bb2];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
--         unreachable;
--     }
-- 
--     bb3: {
-          _0 = _1;
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/simplify_duplicate_unreachable_blocks.rs b/tests/mir-opt/simplify_duplicate_unreachable_blocks.rs
deleted file mode 100644
index d94e6111855..00000000000
--- a/tests/mir-opt/simplify_duplicate_unreachable_blocks.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// skip-filecheck
-#![feature(custom_mir, core_intrinsics)]
-#![crate_type = "lib"]
-
-use std::intrinsics::mir::*;
-
-//@ unit-test: SimplifyCfg-after-uninhabited-enum-branching
-
-// EMIT_MIR simplify_duplicate_unreachable_blocks.assert_nonzero_nonmax.SimplifyCfg-after-uninhabited-enum-branching.diff
-#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
-pub unsafe fn assert_nonzero_nonmax(x: u8) -> u8 {
-    mir!(
-        {
-            match x {
-                0 => unreachable1,
-                u8::MAX => unreachable2,
-                _ => retblock,
-            }
-        }
-        unreachable1 = {
-            Unreachable()
-        }
-        unreachable2 = {
-            Unreachable()
-        }
-        retblock = {
-            RET = x;
-            Return()
-        }
-    )
-}
diff --git a/tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff
index 9ebee3df62c..cc5c642407e 100644
--- a/tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff
@@ -1,7 +1,7 @@
-- // MIR for `expose_addr` before SimplifyLocals-before-const-prop
-+ // MIR for `expose_addr` after SimplifyLocals-before-const-prop
+- // MIR for `expose_provenance` before SimplifyLocals-before-const-prop
++ // MIR for `expose_provenance` after SimplifyLocals-before-const-prop
   
-  fn expose_addr(_1: *const usize) -> () {
+  fn expose_provenance(_1: *const usize) -> () {
       debug p => _1;
       let mut _0: ();
       let _2: usize;
@@ -11,7 +11,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = _1;
-          _2 = move _3 as usize (PointerExposeAddress);
+          _2 = move _3 as usize (PointerExposeProvenance);
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
diff --git a/tests/mir-opt/simplify_locals.rs b/tests/mir-opt/simplify_locals.rs
index f95e9185f44..756679e77e3 100644
--- a/tests/mir-opt/simplify_locals.rs
+++ b/tests/mir-opt/simplify_locals.rs
@@ -63,8 +63,8 @@ fn t4() -> u32 {
     unsafe { X + 1 }
 }
 
-// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff
-fn expose_addr(p: *const usize) {
+// EMIT_MIR simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff
+fn expose_provenance(p: *const usize) {
     // Used pointer to address cast. Has a side effect of exposing the provenance.
     p as usize;
 }
@@ -78,5 +78,5 @@ fn main() {
     t2();
     t3();
     t4();
-    expose_addr(&0);
+    expose_provenance(&0);
 }
diff --git a/tests/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff
index a903e8d789e..526ff2f25cf 100644
--- a/tests/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff
@@ -5,8 +5,6 @@
       let mut _0: ();
 -     let _1: u32;
 -     let mut _2: *mut u32;
-      scope 1 {
-      }
   
       bb0: {
 -         StorageLive(_1);
diff --git a/tests/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff
index e72e71a13a2..a88f6d40115 100644
--- a/tests/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff
@@ -5,8 +5,6 @@
       let mut _0: ();
 -     let _1: &mut u32;
 -     let mut _2: *mut u32;
-      scope 1 {
-      }
   
       bb0: {
 -         StorageLive(_1);
diff --git a/tests/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff
index 37c367c82ca..5d45d7ac781 100644
--- a/tests/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff
@@ -6,8 +6,6 @@
 -     let _1: u32;
 -     let mut _2: &mut u32;
 -     let mut _3: *mut u32;
-      scope 1 {
-      }
   
       bb0: {
 -         StorageLive(_1);
diff --git a/tests/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff
index 006e3c4232d..4f4855dbaaf 100644
--- a/tests/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff
@@ -5,8 +5,6 @@
       let mut _0: u32;
       let mut _1: u32;
       let mut _2: *mut u32;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff
index 6c99d3efd29..2f8dfcc5d63 100644
--- a/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff
@@ -6,8 +6,6 @@
       let mut _0: u32;
       let mut _2: unions::Repr;
       let mut _3: f32;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/tls_access.main.PreCodegen.after.mir b/tests/mir-opt/tls_access.main.PreCodegen.after.mir
index 43c7051f027..1c59e938423 100644
--- a/tests/mir-opt/tls_access.main.PreCodegen.after.mir
+++ b/tests/mir-opt/tls_access.main.PreCodegen.after.mir
@@ -3,12 +3,10 @@
 fn main() -> () {
     let mut _0: ();
     let _1: *mut u8;
+    let _2: &u8;
     let mut _3: *mut u8;
     scope 1 {
-        let _2: &u8;
-        scope 2 {
-            debug a => _2;
-        }
+        debug a => _2;
     }
 
     bb0: {
diff --git a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir
index 89f7016fee4..240f409817d 100644
--- a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir
+++ b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir
@@ -7,8 +7,6 @@ fn process_never(_1: *const !) -> () {
     scope 1 {
         debug _input => _2;
     }
-    scope 2 {
-    }
 
     bb0: {
         unreachable;
diff --git a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir
index 51905f982b8..51514ba5e5d 100644
--- a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir
+++ b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir
@@ -6,8 +6,6 @@ fn process_void(_1: *const Void) -> () {
     scope 1 {
         debug _input => _1;
     }
-    scope 2 {
-    }
 
     bb0: {
         return;
diff --git a/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff
index daff4f9c85b..098b620dfaa 100644
--- a/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff
+++ b/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff
@@ -1,5 +1,5 @@
-- // MIR for `eliminate_fallthrough` before UninhabitedEnumBranching
-+ // MIR for `eliminate_fallthrough` after UninhabitedEnumBranching
+- // MIR for `eliminate_fallthrough` before UnreachableEnumBranching
++ // MIR for `eliminate_fallthrough` after UnreachableEnumBranching
   
   fn eliminate_fallthrough(_1: S) -> u32 {
       debug s => _1;
diff --git a/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff
index 28a8c251d95..995e32b033f 100644
--- a/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
+++ b/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff
@@ -1,5 +1,5 @@
-- // MIR for `keep_fallthrough` before UninhabitedEnumBranching
-+ // MIR for `keep_fallthrough` after UninhabitedEnumBranching
+- // MIR for `keep_fallthrough` before UnreachableEnumBranching
++ // MIR for `keep_fallthrough` after UnreachableEnumBranching
   
   fn keep_fallthrough(_1: S) -> u32 {
       debug s => _1;
diff --git a/tests/mir-opt/uninhabited_fallthrough_elimination.rs b/tests/mir-opt/uninhabited_fallthrough_elimination.rs
index 7dd41aea5ed..537935d8ae4 100644
--- a/tests/mir-opt/uninhabited_fallthrough_elimination.rs
+++ b/tests/mir-opt/uninhabited_fallthrough_elimination.rs
@@ -9,7 +9,7 @@ enum S {
 
 use S::*;
 
-// EMIT_MIR uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
+// EMIT_MIR uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff
 fn keep_fallthrough(s: S) -> u32 {
     match s {
         A(_) => 1,
@@ -18,7 +18,7 @@ fn keep_fallthrough(s: S) -> u32 {
     }
 }
 
-// EMIT_MIR uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff
+// EMIT_MIR uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff
 fn eliminate_fallthrough(s: S) -> u32 {
     match s {
         C => 1,
diff --git a/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir b/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir
index 8edc7b5df88..f0311422c17 100644
--- a/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir
@@ -11,8 +11,6 @@ fn bar(_1: Bar) -> () {
     let mut _7: bool;
     let _8: ();
     let mut _9: [u8; 1];
-    scope 1 {
-    }
 
     bb0: {
         StorageLive(_2);
diff --git a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-abort.diff
index 1b7517c8d01..e5dab5d52a6 100644
--- a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `byref` before UninhabitedEnumBranching
-+ // MIR for `byref` after UninhabitedEnumBranching
+- // MIR for `byref` before UnreachableEnumBranching
++ // MIR for `byref` after UnreachableEnumBranching
   
   fn byref() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-unwind.diff
index 1b7517c8d01..e5dab5d52a6 100644
--- a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `byref` before UninhabitedEnumBranching
-+ // MIR for `byref` after UninhabitedEnumBranching
+- // MIR for `byref` before UnreachableEnumBranching
++ // MIR for `byref` after UnreachableEnumBranching
   
   fn byref() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-abort.diff
index f9a43480917..ea6cdbfbe66 100644
--- a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `custom_discriminant` before UninhabitedEnumBranching
-+ // MIR for `custom_discriminant` after UninhabitedEnumBranching
+- // MIR for `custom_discriminant` before UnreachableEnumBranching
++ // MIR for `custom_discriminant` after UnreachableEnumBranching
   
   fn custom_discriminant() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-unwind.diff
index f9a43480917..ea6cdbfbe66 100644
--- a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `custom_discriminant` before UninhabitedEnumBranching
-+ // MIR for `custom_discriminant` after UninhabitedEnumBranching
+- // MIR for `custom_discriminant` before UnreachableEnumBranching
++ // MIR for `custom_discriminant` after UnreachableEnumBranching
   
   fn custom_discriminant() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-abort.diff
index 383fde4d787..02b9f02f4c0 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t1` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t1` after UninhabitedEnumBranching
+- // MIR for `otherwise_t1` before UnreachableEnumBranching
++ // MIR for `otherwise_t1` after UnreachableEnumBranching
   
   fn otherwise_t1() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-unwind.diff
index 383fde4d787..02b9f02f4c0 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t1` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t1` after UninhabitedEnumBranching
+- // MIR for `otherwise_t1` before UnreachableEnumBranching
++ // MIR for `otherwise_t1` after UnreachableEnumBranching
   
   fn otherwise_t1() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-abort.diff
index 3a2dc19db71..a6d6e0861b1 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t2` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t2` after UninhabitedEnumBranching
+- // MIR for `otherwise_t2` before UnreachableEnumBranching
++ // MIR for `otherwise_t2` after UnreachableEnumBranching
   
   fn otherwise_t2() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-unwind.diff
index 3a2dc19db71..a6d6e0861b1 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t2` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t2` after UninhabitedEnumBranching
+- // MIR for `otherwise_t2` before UnreachableEnumBranching
++ // MIR for `otherwise_t2` after UnreachableEnumBranching
   
   fn otherwise_t2() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-abort.diff
index 5dc1e2b73f6..d3376442376 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t3` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t3` after UninhabitedEnumBranching
+- // MIR for `otherwise_t3` before UnreachableEnumBranching
++ // MIR for `otherwise_t3` after UnreachableEnumBranching
   
   fn otherwise_t3() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-unwind.diff
index 5dc1e2b73f6..d3376442376 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t3` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t3` after UninhabitedEnumBranching
+- // MIR for `otherwise_t3` before UnreachableEnumBranching
++ // MIR for `otherwise_t3` after UnreachableEnumBranching
   
   fn otherwise_t3() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-abort.diff
index 1352dda4971..8f0d5b7cd99 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t4` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4` before UnreachableEnumBranching
++ // MIR for `otherwise_t4` after UnreachableEnumBranching
   
   fn otherwise_t4() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-unwind.diff
index 1352dda4971..8f0d5b7cd99 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t4` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4` before UnreachableEnumBranching
++ // MIR for `otherwise_t4` after UnreachableEnumBranching
   
   fn otherwise_t4() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-abort.diff
index 40dd961fbac..b1ecd008582 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-abort.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t4_uninhabited_default` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4_uninhabited_default` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4_unreachable_default` before UnreachableEnumBranching
++ // MIR for `otherwise_t4_unreachable_default` after UnreachableEnumBranching
   
-  fn otherwise_t4_uninhabited_default() -> () {
+  fn otherwise_t4_unreachable_default() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test4;
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-unwind.diff
index 40dd961fbac..b1ecd008582 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-unwind.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t4_uninhabited_default` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4_uninhabited_default` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4_unreachable_default` before UnreachableEnumBranching
++ // MIR for `otherwise_t4_unreachable_default` after UnreachableEnumBranching
   
-  fn otherwise_t4_uninhabited_default() -> () {
+  fn otherwise_t4_unreachable_default() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test4;
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-abort.diff
index ac39f6be6c6..28c6d4fb675 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-abort.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t4_uninhabited_default_2` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4_uninhabited_default_2` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4_unreachable_default_2` before UnreachableEnumBranching
++ // MIR for `otherwise_t4_unreachable_default_2` after UnreachableEnumBranching
   
-  fn otherwise_t4_uninhabited_default_2() -> () {
+  fn otherwise_t4_unreachable_default_2() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test4;
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-unwind.diff
index ac39f6be6c6..28c6d4fb675 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-unwind.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t4_uninhabited_default_2` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4_uninhabited_default_2` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4_unreachable_default_2` before UnreachableEnumBranching
++ // MIR for `otherwise_t4_unreachable_default_2` after UnreachableEnumBranching
   
-  fn otherwise_t4_uninhabited_default_2() -> () {
+  fn otherwise_t4_unreachable_default_2() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test4;
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-abort.diff
index 8180428a6f4..f36a7efd80d 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-abort.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t5_uninhabited_default` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t5_uninhabited_default` after UninhabitedEnumBranching
+- // MIR for `otherwise_t5_unreachable_default` before UnreachableEnumBranching
++ // MIR for `otherwise_t5_unreachable_default` after UnreachableEnumBranching
   
-  fn otherwise_t5_uninhabited_default() -> () {
+  fn otherwise_t5_unreachable_default() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test5<T>;
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-unwind.diff
index b13d5816aed..20e31c24c84 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-unwind.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t5_uninhabited_default` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t5_uninhabited_default` after UninhabitedEnumBranching
+- // MIR for `otherwise_t5_unreachable_default` before UnreachableEnumBranching
++ // MIR for `otherwise_t5_unreachable_default` after UnreachableEnumBranching
   
-  fn otherwise_t5_uninhabited_default() -> () {
+  fn otherwise_t5_unreachable_default() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test5<T>;
diff --git a/tests/mir-opt/uninhabited_enum_branching.rs b/tests/mir-opt/unreachable_enum_branching.rs
index 6de001be979..156b23657b7 100644
--- a/tests/mir-opt/uninhabited_enum_branching.rs
+++ b/tests/mir-opt/unreachable_enum_branching.rs
@@ -1,4 +1,4 @@
-//@ unit-test: UninhabitedEnumBranching
+//@ unit-test: UnreachableEnumBranching
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 enum Empty {}
@@ -45,7 +45,7 @@ struct Plop {
     test3: Test3,
 }
 
-// EMIT_MIR uninhabited_enum_branching.simple.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.simple.UnreachableEnumBranching.diff
 fn simple() {
     // CHECK-LABEL: fn simple(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -59,7 +59,7 @@ fn simple() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.diff
 fn custom_discriminant() {
     // CHECK-LABEL: fn custom_discriminant(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -72,7 +72,7 @@ fn custom_discriminant() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.diff
 fn otherwise_t1() {
     // CHECK-LABEL: fn otherwise_t1(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -86,7 +86,7 @@ fn otherwise_t1() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.diff
 fn otherwise_t2() {
     // CHECK-LABEL: fn otherwise_t2(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -99,7 +99,7 @@ fn otherwise_t2() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.diff
 fn otherwise_t3() {
     // CHECK-LABEL: fn otherwise_t3(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -116,9 +116,9 @@ fn otherwise_t3() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.diff
-fn otherwise_t4_uninhabited_default() {
-    // CHECK-LABEL: fn otherwise_t4_uninhabited_default(
+// EMIT_MIR unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.diff
+fn otherwise_t4_unreachable_default() {
+    // CHECK-LABEL: fn otherwise_t4_unreachable_default(
     // CHECK: [[discr:_.*]] = discriminant(
     // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb3, 2: bb4, 3: bb1, otherwise: [[unreachable:bb.*]]];
     // CHECK: [[unreachable]]: {
@@ -131,9 +131,9 @@ fn otherwise_t4_uninhabited_default() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.diff
-fn otherwise_t4_uninhabited_default_2() {
-    // CHECK-LABEL: fn otherwise_t4_uninhabited_default_2(
+// EMIT_MIR unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.diff
+fn otherwise_t4_unreachable_default_2() {
+    // CHECK-LABEL: fn otherwise_t4_unreachable_default_2(
     // CHECK: [[discr:_.*]] = discriminant(
     // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb5, 2: bb6, 3: bb1, otherwise: [[unreachable:bb.*]]];
     // CHECK: [[unreachable]]: {
@@ -147,7 +147,7 @@ fn otherwise_t4_uninhabited_default_2() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.diff
 fn otherwise_t4() {
     // CHECK-LABEL: fn otherwise_t4(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -162,9 +162,9 @@ fn otherwise_t4() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.diff
-fn otherwise_t5_uninhabited_default<T>() {
-    // CHECK-LABEL: fn otherwise_t5_uninhabited_default(
+// EMIT_MIR unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.diff
+fn otherwise_t5_unreachable_default<T>() {
+    // CHECK-LABEL: fn otherwise_t5_unreachable_default(
     // CHECK: [[discr:_.*]] = discriminant(
     // CHECK: switchInt(move [[discr]]) -> [255: bb2, 0: bb3, 5: bb4, 3: bb1, otherwise: [[unreachable:bb.*]]];
     // CHECK: [[unreachable]]: {
@@ -177,7 +177,7 @@ fn otherwise_t5_uninhabited_default<T>() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.byref.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.byref.UnreachableEnumBranching.diff
 fn byref() {
     // CHECK-LABEL: fn byref(
     let plop = Plop { xx: 51, test3: Test3::C };
@@ -210,9 +210,9 @@ fn main() {
     otherwise_t1();
     otherwise_t2();
     otherwise_t3();
-    otherwise_t4_uninhabited_default();
-    otherwise_t4_uninhabited_default_2();
+    otherwise_t4_unreachable_default();
+    otherwise_t4_unreachable_default_2();
     otherwise_t4();
-    otherwise_t5_uninhabited_default::<i32>();
+    otherwise_t5_unreachable_default::<i32>();
     byref();
 }
diff --git a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff
index 674d3a25504..a85fc0da992 100644
--- a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `simple` before UninhabitedEnumBranching
-+ // MIR for `simple` after UninhabitedEnumBranching
+- // MIR for `simple` before UnreachableEnumBranching
++ // MIR for `simple` after UnreachableEnumBranching
   
   fn simple() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff
index 674d3a25504..a85fc0da992 100644
--- a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `simple` before UninhabitedEnumBranching
-+ // MIR for `simple` after UninhabitedEnumBranching
+- // MIR for `simple` before UnreachableEnumBranching
++ // MIR for `simple` after UnreachableEnumBranching
   
   fn simple() -> () {
       let mut _0: ();
diff --git a/tests/run-make/core-no-fp-fmt-parse/Makefile b/tests/run-make/core-no-fp-fmt-parse/Makefile
deleted file mode 100644
index 837664d92b9..00000000000
--- a/tests/run-make/core-no-fp-fmt-parse/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-include ../tools.mk
-
-all:
-	$(RUSTC) --edition=2021 -Dwarnings --crate-type=rlib ../../../library/core/src/lib.rs --cfg no_fp_fmt_parse
diff --git a/tests/run-make/core-no-fp-fmt-parse/rmake.rs b/tests/run-make/core-no-fp-fmt-parse/rmake.rs
new file mode 100644
index 00000000000..2748d4359c3
--- /dev/null
+++ b/tests/run-make/core-no-fp-fmt-parse/rmake.rs
@@ -0,0 +1,17 @@
+// This test checks that the core library of Rust can be compiled without enabling
+// support for formatting and parsing floating-point numbers.
+
+extern crate run_make_support;
+
+use run_make_support::rustc;
+use std::path::PathBuf;
+
+fn main() {
+    rustc()
+        .edition("2021")
+        .arg("-Dwarnings")
+        .crate_type("rlib")
+        .input("../../../library/core/src/lib.rs")
+        .cfg("no_fp_fmt_parse")
+        .run();
+}
diff --git a/tests/run-make/hir-tree/Makefile b/tests/run-make/hir-tree/Makefile
deleted file mode 100644
index b0450ea4bc5..00000000000
--- a/tests/run-make/hir-tree/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-include ../tools.mk
-
-# Test that hir-tree output doesn't crash and includes
-# the string constant we would expect to see.
-
-all:
-	$(RUSTC) -o $(TMPDIR)/input.hir -Z unpretty=hir-tree input.rs
-	$(CGREP) '"Hello, Rustaceans!\n"' < $(TMPDIR)/input.hir
diff --git a/tests/run-make/hir-tree/input.rs b/tests/run-make/hir-tree/input.rs
deleted file mode 100644
index 9d1a4e9e47d..00000000000
--- a/tests/run-make/hir-tree/input.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    println!("Hello, Rustaceans!");
-}
diff --git a/tests/run-make/non-unicode-env/non_unicode_env.rs b/tests/run-make/non-unicode-env/non_unicode_env.rs
new file mode 100644
index 00000000000..865fc937365
--- /dev/null
+++ b/tests/run-make/non-unicode-env/non_unicode_env.rs
@@ -0,0 +1,3 @@
+fn main() {
+    let _ = env!("NON_UNICODE_VAR");
+}
diff --git a/tests/run-make/non-unicode-env/non_unicode_env.stderr b/tests/run-make/non-unicode-env/non_unicode_env.stderr
new file mode 100644
index 00000000000..c4dcd7b2eb7
--- /dev/null
+++ b/tests/run-make/non-unicode-env/non_unicode_env.stderr
@@ -0,0 +1,10 @@
+error: environment variable `NON_UNICODE_VAR` is not a valid Unicode string
+ --> non_unicode_env.rs:2:13
+  |
+2 |     let _ = env!("NON_UNICODE_VAR");
+  |             ^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
diff --git a/tests/run-make/non-unicode-env/rmake.rs b/tests/run-make/non-unicode-env/rmake.rs
new file mode 100644
index 00000000000..ba4aa1609b5
--- /dev/null
+++ b/tests/run-make/non-unicode-env/rmake.rs
@@ -0,0 +1,14 @@
+extern crate run_make_support;
+
+use run_make_support::rustc;
+
+fn main() {
+    #[cfg(unix)]
+    let non_unicode: &std::ffi::OsStr = std::os::unix::ffi::OsStrExt::from_bytes(&[0xFF]);
+    #[cfg(windows)]
+    let non_unicode: std::ffi::OsString = std::os::windows::ffi::OsStringExt::from_wide(&[0xD800]);
+    let output = rustc().input("non_unicode_env.rs").env("NON_UNICODE_VAR", non_unicode).run_fail();
+    let actual = std::str::from_utf8(&output.stderr).unwrap();
+    let expected = std::fs::read_to_string("non_unicode_env.stderr").unwrap();
+    assert_eq!(actual, expected);
+}
diff --git a/tests/run-make/remap-path-prefix/Makefile b/tests/run-make/remap-path-prefix/Makefile
index 35f65240ff9..02423dea7d2 100644
--- a/tests/run-make/remap-path-prefix/Makefile
+++ b/tests/run-make/remap-path-prefix/Makefile
@@ -21,19 +21,10 @@ remap-with-scope:
 	grep "/the/aux/lib.rs" $(TMPDIR)/liblib.rmeta || exit 1
 	! grep "$$PWD/auxiliary" $(TMPDIR)/liblib.rmeta || exit 1
 
-	$(RUSTC) --remap-path-prefix $$PWD/auxiliary=/the/aux -Zremap-path-scope=diagnostics $(DEBUGINFOOPTS) --crate-type=lib --emit=metadata auxiliary/lib.rs
-	! grep "/the/aux/lib.rs" $(TMPDIR)/liblib.rmeta || exit 1
-	grep "$$PWD/auxiliary" $(TMPDIR)/liblib.rmeta || exit 1
-
-	$(RUSTC) --remap-path-prefix $$PWD/auxiliary=/the/aux -Zremap-path-scope=diagnostics,object $(DEBUGINFOOPTS) --crate-type=lib --emit=metadata auxiliary/lib.rs
+	$(RUSTC) --remap-path-prefix $$PWD/auxiliary=/the/aux -Zremap-path-scope=macro $(DEBUGINFOOPTS) --crate-type=lib --emit=metadata auxiliary/lib.rs
 	grep "/the/aux/lib.rs" $(TMPDIR)/liblib.rmeta || exit 1
 	! grep "$$PWD/auxiliary" $(TMPDIR)/liblib.rmeta || exit 1
 
-	$(RUSTC) --remap-path-prefix $$PWD/auxiliary=/the/aux -Zremap-path-scope=split-debuginfo $(DEBUGINFOOPTS) --crate-type=lib --emit=metadata auxiliary/lib.rs
-	! grep "/the/aux/lib.rs" $(TMPDIR)/liblib.rmeta || exit 1
-	grep "$$PWD/auxiliary" $(TMPDIR)/liblib.rmeta || exit 1
-
-    # FIXME: We should test the split debuginfo files, but we don't currently a good infra for that
-	$(RUSTC) --remap-path-prefix $$PWD/auxiliary=/the/aux -Zremap-path-scope=split-debuginfo -Zunstable-options -Csplit-debuginfo=packed --crate-type=lib --emit=metadata auxiliary/lib.rs
+	$(RUSTC) --remap-path-prefix $$PWD/auxiliary=/the/aux -Zremap-path-scope=diagnostics,object $(DEBUGINFOOPTS) --crate-type=lib --emit=metadata auxiliary/lib.rs
 	grep "/the/aux/lib.rs" $(TMPDIR)/liblib.rmeta || exit 1
 	! grep "$$PWD/auxiliary" $(TMPDIR)/liblib.rmeta || exit 1
diff --git a/tests/run-make/split-debuginfo/Makefile b/tests/run-make/split-debuginfo/Makefile
index 54eca5c58d7..cb2439093b6 100644
--- a/tests/run-make/split-debuginfo/Makefile
+++ b/tests/run-make/split-debuginfo/Makefile
@@ -142,7 +142,7 @@ packed-remapped-single:
 packed-remapped-scope:
 	$(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=packed -C debuginfo=2 \
 		-Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a \
-		-Z remap-path-scope=split-debuginfo-path foo.rs -g
+		-Z remap-path-scope=debuginfo foo.rs -g
 	objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
 	ls $(TMPDIR)/*.o && exit 1 || exit 0
 	ls $(TMPDIR)/*.dwo && exit 1 || exit 0
@@ -298,7 +298,7 @@ unpacked-remapped-single:
 unpacked-remapped-scope:
 	$(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=unpacked -C debuginfo=2 \
 		-Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a \
-		-Z remap-path-scope=split-debuginfo-path foo.rs -g
+		-Z remap-path-scope=debuginfo foo.rs -g
 	objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
 	rm $(TMPDIR)/*.o
 	ls $(TMPDIR)/*.dwo && exit 1 || exit 0
diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml
index 72e0bcd77e0..3239e54a866 100644
--- a/tests/rustdoc-gui/anchors.goml
+++ b/tests/rustdoc-gui/anchors.goml
@@ -2,7 +2,7 @@
 
 define-function: (
     "check-colors",
-    (theme, main_color, title_color, main_heading_color, main_heading_type_color, src_link_color, sidebar_link_color),
+    [theme, main_color, title_color, main_heading_color, main_heading_type_color, src_link_color, sidebar_link_color],
     block {
         go-to: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
         // This is needed to ensure that the text color is computed.
diff --git a/tests/rustdoc-gui/code-color.goml b/tests/rustdoc-gui/code-color.goml
index 92bdfb25b00..e17af5e7f1f 100644
--- a/tests/rustdoc-gui/code-color.goml
+++ b/tests/rustdoc-gui/code-color.goml
@@ -8,7 +8,7 @@ show-text: true
 
 define-function: (
     "check-colors",
-    (theme, doc_code_color, doc_inline_code_color),
+    [theme, doc_code_color, doc_inline_code_color],
     block {
         // Set the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
diff --git a/tests/rustdoc-gui/codeblock-tooltip.goml b/tests/rustdoc-gui/codeblock-tooltip.goml
index 7be5e39ba47..19e3927f642 100644
--- a/tests/rustdoc-gui/codeblock-tooltip.goml
+++ b/tests/rustdoc-gui/codeblock-tooltip.goml
@@ -4,7 +4,7 @@ show-text: true
 
 define-function: (
     "check-colors",
-    (theme, background, color, border),
+    [theme, background, color, border],
     block {
         // Setting the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
diff --git a/tests/rustdoc-gui/cursor.goml b/tests/rustdoc-gui/cursor.goml
index 27c955f5a13..9412987fc32 100644
--- a/tests/rustdoc-gui/cursor.goml
+++ b/tests/rustdoc-gui/cursor.goml
@@ -8,7 +8,7 @@ assert-css: ("#toggle-all-docs", {"cursor": "pointer"})
 assert-css: ("#copy-path", {"cursor": "pointer"})
 
 // the search tabs
-write: (".search-input", "Foo")
+write-into: (".search-input", "Foo")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml
index a50449e1701..cb7bdaab4c8 100644
--- a/tests/rustdoc-gui/docblock-code-block-line-number.goml
+++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml
@@ -10,7 +10,7 @@ assert-false: "pre.example-line-numbers"
 // Let's now check some CSS properties...
 define-function: (
     "check-colors",
-    (theme, color),
+    [theme, color],
     block {
         // We now set the setting to show the line numbers on code examples.
         set-local-storage: {
diff --git a/tests/rustdoc-gui/docblock-table.goml b/tests/rustdoc-gui/docblock-table.goml
index 678b302f22e..db6d065a4b3 100644
--- a/tests/rustdoc-gui/docblock-table.goml
+++ b/tests/rustdoc-gui/docblock-table.goml
@@ -6,7 +6,7 @@ compare-elements-css: (".impl-items .docblock table td", ".top-doc .docblock tab
 
 define-function: (
     "check-colors",
-    (theme, border_color, zebra_stripe_color),
+    [theme, border_color, zebra_stripe_color],
     block {
         set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
         reload:
diff --git a/tests/rustdoc-gui/escape-key.goml b/tests/rustdoc-gui/escape-key.goml
index 3ea20fd118e..ff8557b9b81 100644
--- a/tests/rustdoc-gui/escape-key.goml
+++ b/tests/rustdoc-gui/escape-key.goml
@@ -2,7 +2,7 @@
 // current content displayed.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // First, we check that the search results are hidden when the Escape key is pressed.
-write: (".search-input", "test")
+write-into: (".search-input", "test")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 wait-for: "#search h1" // The search element is empty before the first search
diff --git a/tests/rustdoc-gui/globals.goml b/tests/rustdoc-gui/globals.goml
index c01c8bb1019..f8c495ec18a 100644
--- a/tests/rustdoc-gui/globals.goml
+++ b/tests/rustdoc-gui/globals.goml
@@ -10,7 +10,7 @@ assert-window-property: {"srcIndex": null}
 
 // Form input
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "Foo")
+write-into: (".search-input", "Foo")
 press-key: 'Enter'
 wait-for: "#search-tabs"
 assert-window-property-false: {"searchIndex": null}
diff --git a/tests/rustdoc-gui/go-to-collapsed-elem.goml b/tests/rustdoc-gui/go-to-collapsed-elem.goml
index 80e9791775e..e56e7ba08cd 100644
--- a/tests/rustdoc-gui/go-to-collapsed-elem.goml
+++ b/tests/rustdoc-gui/go-to-collapsed-elem.goml
@@ -9,14 +9,14 @@ set-property: ("#implementations-list .implementors-toggle", {"open": "false"})
 click: "//*[@class='sidebar']//a[@href='#method.must_use']"
 assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})
 
-define-function: ("collapsed-from-search", (), block {
+define-function: ("collapsed-from-search", [], block {
     // Now we do the same through search result.
     // First we reload the page without the anchor in the URL.
     go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
     // Then we collapse the section again...
     set-property: ("#implementations-list .implementors-toggle", {"open": "false"})
     // Then we run the search.
-    write: (".search-input", "foo::must_use")
+    write-into: (".search-input", "foo::must_use")
     wait-for: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
     click: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
     assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})
diff --git a/tests/rustdoc-gui/headers-color.goml b/tests/rustdoc-gui/headers-color.goml
index 80d11c9c849..2a181c0669f 100644
--- a/tests/rustdoc-gui/headers-color.goml
+++ b/tests/rustdoc-gui/headers-color.goml
@@ -2,7 +2,7 @@
 
 define-function: (
     "check-colors",
-    (theme, color, code_header_color, focus_background_color, headings_color),
+    [theme, color, code_header_color, focus_background_color, headings_color],
     block {
         go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
         // This is needed so that the text color is computed.
diff --git a/tests/rustdoc-gui/headings-anchor.goml b/tests/rustdoc-gui/headings-anchor.goml
index f568caa3b07..9d52c2ac4b5 100644
--- a/tests/rustdoc-gui/headings-anchor.goml
+++ b/tests/rustdoc-gui/headings-anchor.goml
@@ -4,7 +4,7 @@ show-text: true
 
 define-function: (
     "check-heading-anchor",
-    (heading_id),
+    [heading_id],
     block {
         // The anchor should not be displayed by default.
         assert-css: ("#" + |heading_id| + " .doc-anchor", { "display": "none" })
@@ -27,6 +27,6 @@ move-cursor-to: "#top-doc-prose-title"
 // to prevent it from overlapping with the `[-]` element.
 assert-css: ("#top-doc-prose-title:hover .doc-anchor", { "display": "none" })
 
-call-function: ("check-heading-anchor", ("top-doc-prose-sub-heading"))
-call-function: ("check-heading-anchor", ("top-doc-prose-sub-sub-heading"))
-call-function: ("check-heading-anchor", ("you-know-the-drill"))
+call-function: ("check-heading-anchor", {"heading_id": "top-doc-prose-sub-heading"})
+call-function: ("check-heading-anchor", {"heading_id": "top-doc-prose-sub-sub-heading"})
+call-function: ("check-heading-anchor", {"heading_id": "you-know-the-drill"})
diff --git a/tests/rustdoc-gui/headings.goml b/tests/rustdoc-gui/headings.goml
index 102b699b1dd..cdc61e36be2 100644
--- a/tests/rustdoc-gui/headings.goml
+++ b/tests/rustdoc-gui/headings.goml
@@ -156,7 +156,7 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
 
 define-function: (
     "check-colors",
-    (theme, heading_color, small_heading_color, heading_border_color),
+    [theme, heading_color, small_heading_color, heading_border_color],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
@@ -220,7 +220,7 @@ call-function: (
 
 define-function: (
     "check-since-color",
-    (theme),
+    [theme],
     block {
         set-local-storage: {"rustdoc-theme": |theme|}
         reload:
@@ -229,6 +229,6 @@ define-function: (
 )
 
 go-to: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
-call-function: ("check-since-color", ("ayu"))
-call-function: ("check-since-color", ("dark"))
-call-function: ("check-since-color", ("light"))
+call-function: ("check-since-color", {"theme": "ayu"})
+call-function: ("check-since-color", {"theme": "dark"})
+call-function: ("check-since-color", {"theme": "light"})
diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml
index 84c20355500..9a7247a737b 100644
--- a/tests/rustdoc-gui/help-page.goml
+++ b/tests/rustdoc-gui/help-page.goml
@@ -7,17 +7,17 @@ assert-css: ("#help dd", {"font-size": "16px"})
 click: "#help-button > a"
 assert-css: ("#help", {"display": "block"})
 compare-elements-property: (".sub", "#help", ["offsetWidth"])
-compare-elements-position: (".sub", "#help", ("x"))
+compare-elements-position: (".sub", "#help", ["x"])
 set-window-size: (500, 1000) // Try mobile next.
 assert-css: ("#help", {"display": "block"})
 compare-elements-property: (".sub", "#help", ["offsetWidth"])
-compare-elements-position: (".sub", "#help", ("x"))
+compare-elements-position: (".sub", "#help", ["x"])
 
 // Checking the color of the elements of the help menu.
 show-text: true
 define-function: (
     "check-colors",
-    (theme, color, background, box_shadow),
+    [theme, color, background, box_shadow],
     block {
         // Setting the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@@ -60,7 +60,7 @@ assert-css: ("#help dd", {"font-size": "16px"})
 click: "#help-button > a"
 assert-css: ("#help", {"display": "none"})
 compare-elements-property-false: (".sub", "#help", ["offsetWidth"])
-compare-elements-position-false: (".sub", "#help", ("x"))
+compare-elements-position-false: (".sub", "#help", ["x"])
 
 // This test ensures that the "the rustdoc book" anchor link within the help popover works.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
diff --git a/tests/rustdoc-gui/highlight-colors.goml b/tests/rustdoc-gui/highlight-colors.goml
index d162674fa69..48bef319d42 100644
--- a/tests/rustdoc-gui/highlight-colors.goml
+++ b/tests/rustdoc-gui/highlight-colors.goml
@@ -4,7 +4,7 @@ show-text: true
 
 define-function: (
     "check-colors",
-    (
+    [
         theme,
         kw,
         kw2,
@@ -20,7 +20,7 @@ define-function: (
         question_mark,
         comment,
         doc_comment,
-    ),
+    ],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/item-decl-colors.goml b/tests/rustdoc-gui/item-decl-colors.goml
index 7bbd20c4ee0..e68d206a511 100644
--- a/tests/rustdoc-gui/item-decl-colors.goml
+++ b/tests/rustdoc-gui/item-decl-colors.goml
@@ -6,7 +6,7 @@ fail-on-request-error: false
 
 define-function: (
     "check-colors",
-    (
+    [
         theme,
         attr_color,
         trait_color,
@@ -16,7 +16,7 @@ define-function: (
         constant_color,
         fn_color,
         assoc_type_color,
-    ),
+    ],
     block {
         go-to: "file://" + |DOC_PATH| + "/test_docs/struct.WithGenerics.html"
         show-text: true
diff --git a/tests/rustdoc-gui/item-decl-comment-highlighting.goml b/tests/rustdoc-gui/item-decl-comment-highlighting.goml
index 60772693d6c..056b6a5b1e8 100644
--- a/tests/rustdoc-gui/item-decl-comment-highlighting.goml
+++ b/tests/rustdoc-gui/item-decl-comment-highlighting.goml
@@ -4,7 +4,7 @@ show-text: true
 
 define-function: (
     "check-item-decl-comment",
-    (theme, url, comment_color),
+    [theme, url, comment_color],
     block {
         go-to: |url|
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@@ -15,7 +15,7 @@ define-function: (
 
 define-function: (
     "check-items-for-theme",
-    (theme, comment_color),
+    [theme, comment_color],
     block {
         call-function: ("check-item-decl-comment", {
             "theme": |theme|,
diff --git a/tests/rustdoc-gui/item-info-alignment.goml b/tests/rustdoc-gui/item-info-alignment.goml
index 6fc365d1f19..cd0624056b9 100644
--- a/tests/rustdoc-gui/item-info-alignment.goml
+++ b/tests/rustdoc-gui/item-info-alignment.goml
@@ -4,7 +4,7 @@ go-to: "file://" + |DOC_PATH| + "/lib2/struct.ItemInfoAlignmentTest.html"
 
 // First, we try it in "desktop" mode.
 set-window-size: (1200, 870)
-compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x"))
+compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ["x"])
 // Next, we try it in "mobile" mode (max-width: 700px).
 set-window-size: (650, 650)
-compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x"))
+compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ["x"])
diff --git a/tests/rustdoc-gui/item-info.goml b/tests/rustdoc-gui/item-info.goml
index b46d4255ee5..1eb46e832b7 100644
--- a/tests/rustdoc-gui/item-info.goml
+++ b/tests/rustdoc-gui/item-info.goml
@@ -31,13 +31,13 @@ assert-count: ("#main-content > .item-info .stab", 2)
 compare-elements-position-false: (
     "#main-content > .item-info .stab:nth-of-type(1)",
     "#main-content > .item-info .stab:nth-of-type(2)",
-    ("y"),
+    ["y"],
 )
 // But they should have the same `x` position.
 compare-elements-position: (
     "#main-content > .item-info .stab:nth-of-type(1)",
     "#main-content > .item-info .stab:nth-of-type(2)",
-    ("x"),
+    ["x"],
 )
 // They are supposed to have the same height too.
 compare-elements-css: (
diff --git a/tests/rustdoc-gui/jump-to-def-background.goml b/tests/rustdoc-gui/jump-to-def-background.goml
index fa7ed3586dd..ae9c0c560cf 100644
--- a/tests/rustdoc-gui/jump-to-def-background.goml
+++ b/tests/rustdoc-gui/jump-to-def-background.goml
@@ -3,7 +3,7 @@ go-to: "file://" + |DOC_PATH| + "/src/link_to_definition/lib.rs.html"
 
 define-function: (
     "check-background-color",
-    (theme, background_color),
+    [theme, background_color],
     block {
         // Set the theme.
         set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }
@@ -17,6 +17,15 @@ define-function: (
     },
 )
 
-call-function: ("check-background-color", ("ayu", "#333"))
-call-function: ("check-background-color", ("dark", "#333"))
-call-function: ("check-background-color", ("light", "#eee"))
+call-function: ("check-background-color", {
+    "theme": "ayu",
+    "background_color": "#333",
+})
+call-function: ("check-background-color", {
+    "theme": "dark",
+    "background_color": "#333",
+})
+call-function: ("check-background-color", {
+    "theme": "light",
+    "background_color": "#eee",
+})
diff --git a/tests/rustdoc-gui/label-next-to-symbol.goml b/tests/rustdoc-gui/label-next-to-symbol.goml
index d23f9114d36..9a7de60bf38 100644
--- a/tests/rustdoc-gui/label-next-to-symbol.goml
+++ b/tests/rustdoc-gui/label-next-to-symbol.goml
@@ -27,14 +27,14 @@ compare-elements-position-near: (
 compare-elements-position: (
     ".item-name .stab.deprecated",
     ".item-name .stab.portability",
-    ("y"),
+    ["y"],
 )
 
 // Ensure no wrap
 compare-elements-position: (
     "//*[@class='item-name']//a[text()='replaced_function']/..",
     "//*[@class='desc docblock-short'][text()='a thing with a label']",
-    ("y"),
+    ["y"],
 )
 
 // Mobile view
@@ -49,19 +49,19 @@ compare-elements-position-near: (
 compare-elements-position: (
     ".item-name .stab.deprecated",
     ".item-name .stab.portability",
-    ("y"),
+    ["y"],
 )
 
 // Ensure wrap
 compare-elements-position-false: (
     "//*[@class='item-name']//a[text()='replaced_function']/..",
     "//*[@class='desc docblock-short'][text()='a thing with a label']",
-    ("y"),
+    ["y"],
 )
 compare-elements-position-false: (
     ".item-name .stab.deprecated",
     "//*[@class='desc docblock-short'][text()='a thing with a label']",
-    ("y"),
+    ["y"],
 )
 
 // Ensure it doesn't expand.
@@ -72,5 +72,5 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/cfgs/index.html"
 compare-elements-position-false: (
     "//*[@class='stab portability']/code[text()='appservice-api-c']",
     "//*[@class='stab portability']/code[text()='server']",
-    ("y"),
+    ["y"],
 )
diff --git a/tests/rustdoc-gui/links-color.goml b/tests/rustdoc-gui/links-color.goml
index d88ebfb40d7..a1fb619a5d3 100644
--- a/tests/rustdoc-gui/links-color.goml
+++ b/tests/rustdoc-gui/links-color.goml
@@ -6,8 +6,8 @@ show-text: true
 
 define-function: (
     "check-colors",
-    (theme, mod, macro, struct, enum, trait, fn, type, union, keyword,
-     sidebar, sidebar_current, sidebar_current_background),
+    [theme, mod, macro, struct, enum, trait, fn, type, union, keyword,
+     sidebar, sidebar_current, sidebar_current_background],
     block {
         set-local-storage: {
             "rustdoc-theme": |theme|,
diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml
index e10bb538f07..0b1c6622596 100644
--- a/tests/rustdoc-gui/notable-trait.goml
+++ b/tests/rustdoc-gui/notable-trait.goml
@@ -7,13 +7,13 @@ set-window-size: (1100, 600)
 compare-elements-position: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("y"),
+    ["y"],
 )
 // Checking they don't have the same x position.
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("x"),
+    ["x"],
 )
 // The `i` should be *after* the type.
 assert-position: (
@@ -37,7 +37,7 @@ compare-elements-position-near: (
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     "//*[@class='tooltip popover']",
-    ("x")
+    ["x"]
 )
 click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
 move-cursor-to: "//h1"
@@ -48,7 +48,7 @@ set-window-size: (1055, 600)
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("y", "x"),
+    ["y", "x"],
 )
 
 // Now both the `i` and the struct name should be on the next line.
@@ -57,13 +57,13 @@ set-window-size: (980, 600)
 compare-elements-position: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("y"),
+    ["y"],
 )
 // Checking they don't have the same x position.
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("x"),
+    ["x"],
 )
 // The `i` should be *after* the type.
 assert-position: (
@@ -81,13 +81,13 @@ set-window-size: (650, 600)
 compare-elements-position: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("y"),
+    ["y"],
 )
 // Checking they don't have the same x position.
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("x"),
+    ["x"],
 )
 // The `i` should be *after* the type.
 assert-position: (
@@ -109,7 +109,7 @@ compare-elements-position-near: (
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     "//*[@class='tooltip popover']",
-    ("x")
+    ["x"]
 )
 assert-position: (
     "//*[@class='tooltip popover']",
@@ -122,7 +122,7 @@ assert-count: ("//*[@class='tooltip popover']", 0)
 // Now check the colors.
 define-function: (
     "check-colors",
-    (theme, header_color, content_color, type_color, trait_color, link_color),
+    [theme, header_color, content_color, type_color, trait_color, link_color],
     block {
         go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"
         // This is needed to ensure that the text color is computed.
diff --git a/tests/rustdoc-gui/pocket-menu.goml b/tests/rustdoc-gui/pocket-menu.goml
index 404e5740305..b16150cd0d3 100644
--- a/tests/rustdoc-gui/pocket-menu.goml
+++ b/tests/rustdoc-gui/pocket-menu.goml
@@ -31,7 +31,7 @@ assert-css: ("#settings-menu .popover", {"display": "none"})
 
 define-function: (
     "check-popover-colors",
-    (theme, border_color),
+    [theme, border_color],
     block {
         set-local-storage: {
             "rustdoc-theme": |theme|,
diff --git a/tests/rustdoc-gui/run-on-hover.goml b/tests/rustdoc-gui/run-on-hover.goml
index 1f87febcec6..19b15afbac3 100644
--- a/tests/rustdoc-gui/run-on-hover.goml
+++ b/tests/rustdoc-gui/run-on-hover.goml
@@ -7,7 +7,7 @@ show-text: true
 
 define-function: (
     "check-run-button",
-    (theme, color, background, hover_color, hover_background),
+    [theme, color, background, hover_color, hover_background],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/rust-logo.goml b/tests/rustdoc-gui/rust-logo.goml
index dcf3d6bab63..a3b420e5eb9 100644
--- a/tests/rustdoc-gui/rust-logo.goml
+++ b/tests/rustdoc-gui/rust-logo.goml
@@ -3,7 +3,7 @@ go-to: "file://" + |DOC_PATH| + "/staged_api/index.html"
 
 define-function: (
     "check-logo",
-    (theme, filter),
+    [theme, filter],
     block {
         // Going to the doc page.
         go-to: "file://" + |DOC_PATH| + "/staged_api/index.html"
diff --git a/tests/rustdoc-gui/scrape-examples-color.goml b/tests/rustdoc-gui/scrape-examples-color.goml
index 0052d18dc56..b1675a5f1fd 100644
--- a/tests/rustdoc-gui/scrape-examples-color.goml
+++ b/tests/rustdoc-gui/scrape-examples-color.goml
@@ -4,8 +4,8 @@ show-text: true
 
 define-function: (
     "check-colors",
-    (theme, highlight, highlight_focus, help_border, help_color, help_hover_border,
-     help_hover_color),
+    [theme, highlight, highlight_focus, help_border, help_color, help_hover_border,
+     help_hover_color],
     block {
         set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", }
         reload:
@@ -64,7 +64,7 @@ go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html"
 
 define-function: (
     "check-background",
-    (theme, background_color_start, background_color_end),
+    [theme, background_color_start, background_color_end],
     block {
         set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", }
         reload:
diff --git a/tests/rustdoc-gui/scrape-examples-toggle.goml b/tests/rustdoc-gui/scrape-examples-toggle.goml
index f742b3186e5..ea645d28924 100644
--- a/tests/rustdoc-gui/scrape-examples-toggle.goml
+++ b/tests/rustdoc-gui/scrape-examples-toggle.goml
@@ -5,7 +5,7 @@ go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
 show-text: true
 define-function: (
     "check-color",
-    (theme, toggle_line_color, toggle_line_hover_color),
+    [theme, toggle_line_color, toggle_line_hover_color],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/search-corrections.goml b/tests/rustdoc-gui/search-corrections.goml
index aeb3c9b31a3..b81b1f382a9 100644
--- a/tests/rustdoc-gui/search-corrections.goml
+++ b/tests/rustdoc-gui/search-corrections.goml
@@ -4,7 +4,7 @@
 // First, try a search-by-name
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Intentionally wrong spelling of "NotableStructWithLongName"
-write: (".search-input", "NotableStructWithLongNamr")
+write-into: (".search-input", "NotableStructWithLongNamr")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -41,7 +41,7 @@ assert-text: (
 // Now, explicit return values
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Intentionally wrong spelling of "NotableStructWithLongName"
-write: (".search-input", "-> NotableStructWithLongNamr")
+write-into: (".search-input", "-> NotableStructWithLongNamr")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -58,7 +58,7 @@ assert-text: (
 // Now, generic correction
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Intentionally wrong spelling of "NotableStructWithLongName"
-write: (".search-input", "NotableStructWithLongNamr, NotableStructWithLongNamr")
+write-into: (".search-input", "NotableStructWithLongNamr, NotableStructWithLongNamr")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -75,7 +75,7 @@ assert-text: (
 // Now, generic correction plus error
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Intentionally wrong spelling of "NotableStructWithLongName"
-write: (".search-input", "Foo<NotableStructWithLongNamr>,y")
+write-into: (".search-input", "Foo<NotableStructWithLongNamr>,y")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -91,7 +91,7 @@ assert-text: (
 
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Intentionally wrong spelling of "NotableStructWithLongName"
-write: (".search-input", "generic:NotableStructWithLongNamr<x>,y")
+write-into: (".search-input", "generic:NotableStructWithLongNamr<x>,y")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-error.goml b/tests/rustdoc-gui/search-error.goml
index 70aeda1769a..d3de77b5635 100644
--- a/tests/rustdoc-gui/search-error.goml
+++ b/tests/rustdoc-gui/search-error.goml
@@ -4,7 +4,7 @@ show-text: true
 
 define-function: (
     "check-colors",
-    (theme, error_background),
+    [theme, error_background],
     block {
         // Setting the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
diff --git a/tests/rustdoc-gui/search-filter.goml b/tests/rustdoc-gui/search-filter.goml
index 9e2855b5e02..8c50322fcd4 100644
--- a/tests/rustdoc-gui/search-filter.goml
+++ b/tests/rustdoc-gui/search-filter.goml
@@ -1,7 +1,7 @@
 // Checks that the crate search filtering is handled correctly and changes the results.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 show-text: true
-write: (".search-input", "test")
+write-into: (".search-input", "test")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-form-elements.goml b/tests/rustdoc-gui/search-form-elements.goml
index 0ea61a4f0eb..2fc66259291 100644
--- a/tests/rustdoc-gui/search-form-elements.goml
+++ b/tests/rustdoc-gui/search-form-elements.goml
@@ -4,10 +4,10 @@ show-text: true
 
 define-function: (
     "check-search-colors",
-    (
+    [
         theme, border, background, search_input_color, search_input_border_focus,
         menu_button_border, menu_button_a_color, menu_button_a_border_hover, menu_a_color,
-    ),
+    ],
     block {
         set-local-storage: {
             "rustdoc-theme": |theme|,
diff --git a/tests/rustdoc-gui/search-keyboard.goml b/tests/rustdoc-gui/search-keyboard.goml
index f1d8024616b..707bb8f5faa 100644
--- a/tests/rustdoc-gui/search-keyboard.goml
+++ b/tests/rustdoc-gui/search-keyboard.goml
@@ -1,7 +1,7 @@
 // Checks that the search tab results work correctly with function signature syntax
 // First, try a search-by-name
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "Foo")
+write-into: (".search-input", "Foo")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-no-result.goml b/tests/rustdoc-gui/search-no-result.goml
index e7c64791256..dda50ec3fb6 100644
--- a/tests/rustdoc-gui/search-no-result.goml
+++ b/tests/rustdoc-gui/search-no-result.goml
@@ -4,7 +4,7 @@ show-text: true
 
 define-function: (
     "check-no-result",
-    (theme, link, link_hover),
+    [theme, link, link_hover],
     block {
         // Changing theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
diff --git a/tests/rustdoc-gui/search-reexport.goml b/tests/rustdoc-gui/search-reexport.goml
index b9d2c8f15ce..2e7c967d5c3 100644
--- a/tests/rustdoc-gui/search-reexport.goml
+++ b/tests/rustdoc-gui/search-reexport.goml
@@ -6,7 +6,7 @@ reload:
 // First we check that the reexport has the correct ID and no background color.
 assert-text: ("//*[@id='reexport.TheStdReexport']", "pub use ::std as TheStdReexport;")
 assert-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgba(0, 0, 0, 0)"})
-write: (".search-input", "TheStdReexport")
+write-into: (".search-input", "TheStdReexport")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 wait-for: "//a[@class='result-import']"
@@ -22,7 +22,7 @@ wait-for-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "#494a
 // We now check that the alias is working as well on the reexport.
 // To be SURE that the search will be run.
 press-key: 'Enter'
-write: (".search-input", "AliasForTheStdReexport")
+write-into: (".search-input", "AliasForTheStdReexport")
 wait-for: "//a[@class='result-import']"
 assert-text: (
     "a.result-import .result-name",
diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml
index 44677dfbfef..1a19ea2d843 100644
--- a/tests/rustdoc-gui/search-result-color.goml
+++ b/tests/rustdoc-gui/search-result-color.goml
@@ -2,7 +2,7 @@
 
 define-function: (
     "check-result-color",
-    (result_kind, color, hover_color),
+    [result_kind, color, hover_color],
     block {
         assert-css: (".result-" + |result_kind| + " ." + |result_kind|, {"color": |color|}, ALL)
         assert-css: (
@@ -78,60 +78,60 @@ store-value: (hover_background_color, "#3c3c3c") // hover background color
 store-value: (grey, "#999")
 
 call-function: (
-    "check-result-color", (
-        "keyword", // item kind
-        "#39afd7", // color of item kind
-        "#39afd7", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "keyword",
+        "color": "#39afd7",
+        "hover_color": "#39afd7",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "struct", // item kind
-        "#ffa0a5", // color of item kind
-        "#ffa0a5", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "struct",
+        "color": "#ffa0a5",
+        "hover_color": "#ffa0a5",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "associatedtype", // item kind
-        "#39afd7", // color of item kind
-        "#39afd7", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "associatedtype",
+        "color": "#39afd7",
+        "hover_color": "#39afd7",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "tymethod", // item kind
-        "#fdd687", // color of item kind
-        "#fdd687", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "tymethod",
+        "color": "#fdd687",
+        "hover_color": "#fdd687",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "method", // item kind
-        "#fdd687", // color of item kind
-        "#fdd687", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "method",
+        "color": "#fdd687",
+        "hover_color": "#fdd687",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "structfield", // item kind
-        "#0096cf", // color of item kind
-        "#fff", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "structfield",
+        "color": "#0096cf",
+        "hover_color": "#fff",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "macro", // item kind
-        "#a37acc", // color of item kind
-        "#a37acc", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "macro",
+        "color": "#a37acc",
+        "hover_color": "#a37acc",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "fn", // item kind
-        "#fdd687", // color of item kind
-        "#fdd687", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "fn",
+        "color": "#fdd687",
+        "hover_color": "#fdd687",
+    },
 )
 
 // Checking the `<a>` container.
@@ -190,60 +190,60 @@ store-value: (hover_background_color, "#616161") // hover background color
 store-value: (grey, "#ccc")
 
 call-function: (
-    "check-result-color", (
-        "keyword", // item kind
-        "#d2991d", // color of item kind
-        "#d2991d", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "keyword",
+        "color": "#d2991d",
+        "hover_color": "#d2991d",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "struct", // item kind
-        "#2dbfb8", // color of item kind
-        "#2dbfb8", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "struct",
+        "color": "#2dbfb8",
+        "hover_color": "#2dbfb8",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "associatedtype", // item kind
-        "#d2991d", // color of item kind
-        "#d2991d", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "associatedtype",
+        "color": "#d2991d",
+        "hover_color": "#d2991d",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "tymethod", // item kind
-        "#2bab63", // color of item kind
-        "#2bab63", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "tymethod",
+        "color": "#2bab63",
+        "hover_color": "#2bab63",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "method", // item kind
-        "#2bab63", // color of item kind
-        "#2bab63", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "method",
+        "color": "#2bab63",
+        "hover_color": "#2bab63",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "structfield", // item kind
-        "#ddd", // color of item kind
-        "#ddd", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "structfield",
+        "color": "#ddd",
+        "hover_color": "#ddd",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "macro", // item kind
-        "#09bd00", // color of item kind
-        "#09bd00", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "macro",
+        "color": "#09bd00",
+        "hover_color": "#09bd00",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "fn", // item kind
-        "#2bab63", // color of item kind
-        "#2bab63", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "fn",
+        "color": "#2bab63",
+        "hover_color": "#2bab63",
+    },
 )
 
 // Checking the `<a>` container.
@@ -287,60 +287,60 @@ store-value: (hover_background_color, "#ccc") // hover background color
 store-value: (grey, "#999")
 
 call-function: (
-    "check-result-color", (
-        "keyword", // item kind
-        "#3873ad", // color of item kind
-        "#3873ad", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "keyword",
+        "color": "#3873ad",
+        "hover_color": "#3873ad",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "struct", // item kind
-        "#ad378a", // color of item kind
-        "#ad378a", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "struct",
+        "color": "#ad378a",
+        "hover_color": "#ad378a",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "associatedtype", // item kind
-        "#3873ad", // color of item kind
-        "#3873ad", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "associatedtype",
+        "color": "#3873ad",
+        "hover_color": "#3873ad",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "tymethod", // item kind
-        "#ad7c37", // color of item kind
-        "#ad7c37", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "tymethod",
+        "color": "#ad7c37",
+        "hover_color": "#ad7c37",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "method", // item kind
-        "#ad7c37", // color of item kind
-        "#ad7c37", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "method",
+        "color": "#ad7c37",
+        "hover_color": "#ad7c37",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "structfield", // item kind
-        "#000", // color of item kind
-        "#000", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "structfield",
+        "color": "#000",
+        "hover_color": "#000",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "macro", // item kind
-        "#068000", // color of item kind
-        "#068000", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "macro",
+        "color": "#068000",
+        "hover_color": "#068000",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "fn", // item kind
-        "#ad7c37", // color of item kind
-        "#ad7c37", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "fn",
+        "color": "#ad7c37",
+        "hover_color": "#ad7c37",
+    },
 )
 
 // Checking the `<a>` container.
@@ -358,11 +358,11 @@ show-text: true
 
 define-function: (
     "check-alias",
-    (theme, alias, grey),
+    [theme, alias, grey],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
-        write: (".search-input", "thisisanalias")
+        write-into: (".search-input", "thisisanalias")
         // To be SURE that the search will be run.
         press-key: 'Enter'
         // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-result-display.goml b/tests/rustdoc-gui/search-result-display.goml
index 6ce13b8c3d3..b1a5548808e 100644
--- a/tests/rustdoc-gui/search-result-display.goml
+++ b/tests/rustdoc-gui/search-result-display.goml
@@ -2,7 +2,7 @@
 // Checks that the search results have the expected width.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 set-window-size: (900, 1000)
-write: (".search-input", "test")
+write-into: (".search-input", "test")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 wait-for: "#crate-search"
@@ -69,7 +69,7 @@ assert-css: ("#search", {"width": "640px"})
 show-text: true
 define-function: (
     "check-filter",
-    (theme, border, filter, hover_border, hover_filter),
+    [theme, border, filter, hover_border, hover_filter],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/search-result-impl-disambiguation.goml b/tests/rustdoc-gui/search-result-impl-disambiguation.goml
index 6d12032e891..3e49ac33025 100644
--- a/tests/rustdoc-gui/search-result-impl-disambiguation.goml
+++ b/tests/rustdoc-gui/search-result-impl-disambiguation.goml
@@ -5,7 +5,7 @@
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 
 // This should link to the inherent impl
-write: (".search-input", "ZyxwvutMethodDisambiguation -> bool")
+write-into: (".search-input", "ZyxwvutMethodDisambiguation -> bool")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -25,7 +25,7 @@ assert: "section:target"
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 
 // This should link to the trait impl
-write: (".search-input", "ZyxwvutMethodDisambiguation, usize -> usize")
+write-into: (".search-input", "ZyxwvutMethodDisambiguation, usize -> usize")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-result-keyword.goml b/tests/rustdoc-gui/search-result-keyword.goml
index 1b2be6d4e3e..370edce2ddd 100644
--- a/tests/rustdoc-gui/search-result-keyword.goml
+++ b/tests/rustdoc-gui/search-result-keyword.goml
@@ -1,6 +1,6 @@
 // Checks that the "keyword" results have the expected text alongside them.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "CookieMonster")
+write-into: (".search-input", "CookieMonster")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml b/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml
index 156d8d03ca2..7e26229ec6e 100644
--- a/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml
+++ b/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml
@@ -1,7 +1,7 @@
 // Checks that the search tab results work correctly with function signature syntax
 // First, try a search-by-name
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "Foo")
+write-into: (".search-input", "Foo")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -23,7 +23,7 @@ wait-for-attribute: ("#search-tabs > button:nth-of-type(3)", {"class": "selected
 
 // Now try search-by-return
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "-> String")
+write-into: (".search-input", "-> String")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -45,7 +45,7 @@ wait-for-attribute: ("#search-tabs > button:nth-of-type(1)", {"class": "selected
 
 // Try with a search-by-return with no results
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "-> Something")
+write-into: (".search-input", "-> Something")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -55,7 +55,7 @@ assert-text: ("#search-tabs > button:nth-of-type(1)", "In Function Return Types"
 
 // Try with a search-by-parameter
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "usize,pattern")
+write-into: (".search-input", "usize,pattern")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -65,7 +65,7 @@ assert-text: ("#search-tabs > button:nth-of-type(1)", "In Function Parameters",
 
 // Try with a search-by-parameter-and-return
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "pattern -> str")
+write-into: (".search-input", "pattern -> str")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-tab.goml b/tests/rustdoc-gui/search-tab.goml
index b52bb0688c1..c33866593c3 100644
--- a/tests/rustdoc-gui/search-tab.goml
+++ b/tests/rustdoc-gui/search-tab.goml
@@ -4,9 +4,9 @@ show-text: true
 
 define-function: (
     "check-colors",
-    (theme, background, background_selected, background_hover, border_bottom,
+    [theme, background, background_selected, background_hover, border_bottom,
      border_bottom_selected, border_bottom_hover, border_top, border_top_selected,
-     border_top_hover),
+     border_top_hover],
     block {
         // Setting the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@@ -93,12 +93,12 @@ assert-property: ("#search-tabs > button:nth-child(3) > .count", {"offsetWidth":
 compare-elements-position: (
     "#search-tabs > button:nth-child(1) > .count",
     "#search-tabs > button:nth-child(2) > .count",
-    ("y")
+    ["y"]
 )
 compare-elements-position: (
     "#search-tabs > button:nth-child(2) > .count",
     "#search-tabs > button:nth-child(3) > .count",
-    ("y")
+    ["y"]
 )
 // Check that counts are beside the titles and haven't wrapped
 compare-elements-position-near: (
@@ -135,12 +135,12 @@ assert-property: ("#search-tabs > button:nth-child(3) > .count", {"offsetWidth":
 compare-elements-position: (
     "#search-tabs > button:nth-child(1) > .count",
     "#search-tabs > button:nth-child(2) > .count",
-    ("y")
+    ["y"]
 )
 compare-elements-position: (
     "#search-tabs > button:nth-child(2) > .count",
     "#search-tabs > button:nth-child(3) > .count",
-    ("y")
+    ["y"]
 )
 // Check that counts are NOT beside the titles; now they have wrapped
 compare-elements-position-near-false: (
diff --git a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml
index b55a1cfd92b..9afde7c61da 100644
--- a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml
+++ b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml
@@ -6,7 +6,7 @@ fail-on-request-error: false
 
 define-function: (
     "check-setting",
-    (storage_value, setting_attribute_value, toggle_attribute_value),
+    [storage_value, setting_attribute_value, toggle_attribute_value],
     block {
         assert-local-storage: {"rustdoc-auto-hide-large-items": |storage_value|}
         click: "#settings-menu"
diff --git a/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml b/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml
index 5210ad8f793..644396ed578 100644
--- a/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml
+++ b/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml
@@ -3,7 +3,7 @@
 
 define-function: (
     "check-setting",
-    (storage_value, setting_attribute_value, toggle_attribute_value),
+    [storage_value, setting_attribute_value, toggle_attribute_value],
     block {
         assert-local-storage: {"rustdoc-auto-hide-method-docs": |storage_value|}
         click: "#settings-menu"
diff --git a/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml b/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml
index ecadd8fa80e..3c09198dae5 100644
--- a/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml
+++ b/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml
@@ -2,7 +2,7 @@
 
 define-function: (
     "check-setting",
-    (storage_value, setting_attribute_value, toggle_attribute_value),
+    [storage_value, setting_attribute_value, toggle_attribute_value],
     block {
         assert-local-storage: {"rustdoc-auto-hide-trait-implementations": |storage_value|}
         click: "#settings-menu"
diff --git a/tests/rustdoc-gui/setting-go-to-only-result.goml b/tests/rustdoc-gui/setting-go-to-only-result.goml
index 45e0b349051..f8535477c22 100644
--- a/tests/rustdoc-gui/setting-go-to-only-result.goml
+++ b/tests/rustdoc-gui/setting-go-to-only-result.goml
@@ -2,7 +2,7 @@
 
 define-function: (
     "check-setting",
-    (storage_value, setting_attribute_value),
+    [storage_value, setting_attribute_value],
     block {
         assert-local-storage: {"rustdoc-go-to-only-result": |storage_value|}
         click: "#settings-menu"
@@ -32,7 +32,7 @@ assert-local-storage: {"rustdoc-go-to-only-result": "true"}
 
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
 // We enter it into the search.
-write: (".search-input", "HasALongTraitWithParams")
+write-into: (".search-input", "HasALongTraitWithParams")
 wait-for-document-property: {"title": "HasALongTraitWithParams in lib2 - Rust"}
 assert-window-property: ({"location": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH)
 
diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml
index e40c637dcf7..0bb21c28cb5 100644
--- a/tests/rustdoc-gui/settings.goml
+++ b/tests/rustdoc-gui/settings.goml
@@ -304,7 +304,7 @@ wait-for: "#settings"
 assert-css: (".setting-radio", {"cursor": "pointer"})
 
 assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
-compare-elements-position: (".sub form", "#settings", ("x"))
+compare-elements-position: (".sub form", "#settings", ["x"])
 
 // Check that setting-line has the same margin in this mode as in the popover.
 assert-css: (".setting-line", {"margin": |setting_line_margin|})
diff --git a/tests/rustdoc-gui/sidebar-links-color.goml b/tests/rustdoc-gui/sidebar-links-color.goml
index 774fbcac1e2..0edffc51a81 100644
--- a/tests/rustdoc-gui/sidebar-links-color.goml
+++ b/tests/rustdoc-gui/sidebar-links-color.goml
@@ -6,12 +6,12 @@ show-text: true
 
 define-function: (
     "check-colors",
-    (
+    [
         theme, struct, struct_hover, struct_hover_background, enum, enum_hover,
         enum_hover_background, union, union_hover, union_hover_background, trait, trait_hover,
         trait_hover_background, fn, fn_hover, fn_hover_background, type, type_hover,
         type_hover_background, keyword, keyword_hover, keyword_hover_background,
-    ),
+    ],
     block {
         set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }
         reload:
diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml
index d3a82d9ebe6..8843de8d7e9 100644
--- a/tests/rustdoc-gui/sidebar-mobile.goml
+++ b/tests/rustdoc-gui/sidebar-mobile.goml
@@ -57,7 +57,7 @@ show-text: true
 
 define-function: (
     "check-colors",
-    (theme, color, background),
+    [theme, color, background],
     block {
         set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
         reload:
diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml
index 5149d4991f7..41c8e45f4a6 100644
--- a/tests/rustdoc-gui/sidebar-source-code-display.goml
+++ b/tests/rustdoc-gui/sidebar-source-code-display.goml
@@ -30,9 +30,9 @@ show-text: true
 
 define-function: (
     "check-colors",
-    (
+    [
         theme, color, color_hover, background, background_hover, background_toggle,
-    ),
+    ],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/sidebar-source-code.goml b/tests/rustdoc-gui/sidebar-source-code.goml
index d7de43a2243..3f7ef643d18 100644
--- a/tests/rustdoc-gui/sidebar-source-code.goml
+++ b/tests/rustdoc-gui/sidebar-source-code.goml
@@ -6,7 +6,7 @@ show-text: true
 // First, check the sidebar colors.
 define-function: (
     "check-colors",
-    (theme, color, background_color),
+    [theme, color, background_color],
     block {
         set-local-storage: {
             "rustdoc-theme": |theme|,
diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml
index 82b4f2e9429..115b1eb323c 100644
--- a/tests/rustdoc-gui/sidebar.goml
+++ b/tests/rustdoc-gui/sidebar.goml
@@ -6,7 +6,7 @@ show-text: true
 // First, check the sidebar colors.
 define-function: (
     "check-colors",
-    (theme, color, background_color),
+    [theme, color, background_color],
     block {
         set-local-storage: {
             "rustdoc-theme": |theme|,
diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml
index 8b4d7617e0c..e29d123d227 100644
--- a/tests/rustdoc-gui/source-code-page.goml
+++ b/tests/rustdoc-gui/source-code-page.goml
@@ -21,7 +21,7 @@ assert-attribute-false: (".src-line-numbers > a:nth-child(7)", {"class": "line-h
 
 define-function: (
     "check-colors",
-    (theme, color, background_color, highlight_color, highlight_background_color),
+    [theme, color, background_color, highlight_color, highlight_background_color],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
@@ -61,7 +61,7 @@ call-function: ("check-colors", {
 })
 
 // This is to ensure that the content is correctly align with the line numbers.
-compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
+compare-elements-position: ("//*[@id='1']", ".rust > code > span", ["y"])
 // Check the `href` property so that users can treat anchors as links.
 assert-property: (".src-line-numbers > a:nth-child(1)", {
     "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#1"
@@ -122,7 +122,7 @@ store-property: (
 )
 define-function: (
     "check-sidebar-dir-entry",
-    (x, y),
+    [x, y],
     block {
         assert: "details:first-of-type.dir-entry[open] > summary::marker"
         assert-css: ("#src-sidebar > details:first-of-type.dir-entry", {"padding-left": "4px"})
diff --git a/tests/rustdoc-gui/stab-badge.goml b/tests/rustdoc-gui/stab-badge.goml
index bb3d2aaa3dc..46df0946c45 100644
--- a/tests/rustdoc-gui/stab-badge.goml
+++ b/tests/rustdoc-gui/stab-badge.goml
@@ -3,7 +3,7 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 show-text: true
 define-function: (
     "check-badge",
-    (theme, background, color),
+    [theme, background, color],
     block {
         set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
         go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
diff --git a/tests/rustdoc-gui/target.goml b/tests/rustdoc-gui/target.goml
index 26071df8d04..0f8f7709363 100644
--- a/tests/rustdoc-gui/target.goml
+++ b/tests/rustdoc-gui/target.goml
@@ -7,7 +7,7 @@ assert: "#method\.a_method:target"
 
 define-function: (
     "check-style",
-    (theme, background, border),
+    [theme, background, border],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/toggle-docs.goml b/tests/rustdoc-gui/toggle-docs.goml
index 9ea6d9b18f4..cfd18bd2e14 100644
--- a/tests/rustdoc-gui/toggle-docs.goml
+++ b/tests/rustdoc-gui/toggle-docs.goml
@@ -49,7 +49,7 @@ assert-attribute: ("details.toggle", {"open": ""}, ALL)
 show-text: true
 define-function: (
     "check-color",
-    (theme, filter),
+    [theme, filter],
     block {
         // Setting the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
diff --git a/tests/rustdoc-gui/type-declation-overflow.goml b/tests/rustdoc-gui/type-declation-overflow.goml
index a97cc98897a..3709aa10266 100644
--- a/tests/rustdoc-gui/type-declation-overflow.goml
+++ b/tests/rustdoc-gui/type-declation-overflow.goml
@@ -47,18 +47,18 @@ assert-css: (".mobile-topbar h2", {"overflow-x": "hidden"})
 // On desktop, they wrap when too big.
 set-window-size: (1100, 800)
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
-compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y"))
+compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
-compare-elements-position: (".main-heading h1", ".main-heading .out-of-band", ("y"))
+compare-elements-position: (".main-heading h1", ".main-heading .out-of-band", ["y"])
 // make sure there is a gap between them
 compare-elements-position-near-false: (".main-heading h1", ".main-heading .out-of-band", {"x": 550})
 
 // On mobile, they always wrap.
 set-window-size: (600, 600)
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
-compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y"))
+compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
-compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y"))
+compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
 
 // Now we will check that the scrolling is working.
 // First on an item with "hidden methods".
diff --git a/tests/rustdoc-gui/unsafe-fn.goml b/tests/rustdoc-gui/unsafe-fn.goml
index 8d26f15f37f..83503121a04 100644
--- a/tests/rustdoc-gui/unsafe-fn.goml
+++ b/tests/rustdoc-gui/unsafe-fn.goml
@@ -13,7 +13,7 @@ define-function: (
     "sup-check",
     // `theme` is the theme being tested.
     // `color` is the expected color of the `<sup>` element.
-    (theme, color),
+    [theme, color],
     block {
         // Set the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@@ -23,6 +23,15 @@ define-function: (
     },
 )
 
-call-function: ("sup-check", ("ayu", "#c5c5c5"))
-call-function: ("sup-check", ("dark", "#ddd"))
-call-function: ("sup-check", ("light", "black"))
+call-function: ("sup-check", {
+    "theme": "ayu",
+    "color": "#c5c5c5",
+})
+call-function: ("sup-check", {
+    "theme": "dark",
+    "color": "#ddd",
+})
+call-function: ("sup-check", {
+    "theme": "light",
+    "color": "black",
+})
diff --git a/tests/rustdoc-gui/warning-block.goml b/tests/rustdoc-gui/warning-block.goml
index 10e206049f5..a5a47f868db 100644
--- a/tests/rustdoc-gui/warning-block.goml
+++ b/tests/rustdoc-gui/warning-block.goml
@@ -5,7 +5,7 @@ show-text: true
 store-value: (default_y_pos, 5)
 define-function: (
     "check-warning",
-    (theme, color, border_color),
+    [theme, color, border_color],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/where-whitespace.goml b/tests/rustdoc-gui/where-whitespace.goml
index da104fa4011..823ce970407 100644
--- a/tests/rustdoc-gui/where-whitespace.goml
+++ b/tests/rustdoc-gui/where-whitespace.goml
@@ -3,25 +3,25 @@ go-to: "file://" + |DOC_PATH| + "/lib2/trait.Whitespace.html"
 show-text: true
 // First, we check in the trait definition if the where clause is "on its own" (not on the same
 // line than "pub trait Whitespace<Idx>").
-compare-elements-position-false: (".item-decl code", "div.where", ("y"))
+compare-elements-position-false: (".item-decl code", "div.where", ["y"])
 // And that the code following it isn't on the same line either.
-compare-elements-position-false: (".item-decl .fn", "div.where", ("y"))
+compare-elements-position-false: (".item-decl .fn", "div.where", ["y"])
 
 go-to: "file://" + |DOC_PATH| + "/lib2/struct.WhereWhitespace.html"
 // We make the screen a bit wider to ensure that the trait impl is on one line.
 set-window-size: (915, 915)
 
-compare-elements-position-false: ("#method\.new .fn", "#method\.new div.where", ("y"))
+compare-elements-position-false: ("#method\.new .fn", "#method\.new div.where", ["y"])
 // We ensure that both the trait name and the struct name are on the same line in
 // "impl<K, T> Whitespace<&K> for WhereWhitespace<T>".
 compare-elements-position: (
     "#trait-implementations-list .impl h3 .trait",
     "#trait-implementations-list .impl h3 .struct",
-    ("y"),
+    ["y"],
 )
 // And we now check that the where condition isn't on the same line.
 compare-elements-position-false: (
     "#trait-implementations-list .impl h3 .trait",
     "#trait-implementations-list .impl h3 div.where",
-    ("y"),
+    ["y"],
 )
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/const-in-super-trait-and-item-bound.rs b/tests/rustdoc-ui/synthetic-auto-trait-impls/const-in-super-trait-and-item-bound.rs
new file mode 100644
index 00000000000..df6de6769d5
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/const-in-super-trait-and-item-bound.rs
@@ -0,0 +1,23 @@
+// We used to ICE here while trying to synthesize auto trait impls.
+// issue: 107715
+//@ check-pass
+
+pub const N: usize = 1;
+
+pub struct MapType<K: Supertrait<V>, V> {
+    _array: K::Array,
+}
+
+pub trait Subtrait: Supertrait<[u8; N]> {}
+
+pub trait Supertrait<V> {
+    type Array: AnotherTrait<V>;
+}
+
+pub trait AnotherTrait<V> {
+    const LENGTH: usize;
+}
+
+pub struct Container<S: Subtrait> {
+    _x: MapType<S, [u8; N]>,
+}
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl-normalize.rs b/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl-normalize.rs
new file mode 100644
index 00000000000..1b67c2bc875
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl-normalize.rs
@@ -0,0 +1,17 @@
+// We used to ICE here while trying to synthesize auto trait impls.
+// issue: 112242
+//@ check-pass
+//@ compile-flags: -Znormalize-docs
+
+pub trait MyTrait<'a> {
+    type MyItem;
+}
+pub struct Inner<Q>(Q);
+pub struct Outer<Q>(Inner<Q>);
+
+impl<'a, Q> std::marker::Unpin for Inner<Q>
+where
+    Q: MyTrait<'a>,
+    <Q as MyTrait<'a>>::MyItem: Copy,
+{
+}
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl.rs b/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl.rs
new file mode 100644
index 00000000000..31d1b11ff31
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl.rs
@@ -0,0 +1,11 @@
+// We used to ICE here while trying to synthesize auto trait impls.
+// issue: 123370
+//@ check-pass
+
+pub struct Inner<'a, Q>(&'a (), Q);
+
+pub struct Outer<'a, Q>(Inner<'a, Q>);
+
+impl<'a, Q: Trait<'a>> std::marker::Unpin for Inner<'static, Q> {}
+
+pub trait Trait<'a> {}
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.rs b/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.rs
new file mode 100644
index 00000000000..f62f8396e99
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.rs
@@ -0,0 +1,18 @@
+// We used to ICE here while trying to synthesize auto trait impls.
+// issue: 114657
+
+pub trait Foo {
+    type FooType;
+}
+
+pub trait Bar<const A: usize>: Foo<FooType = <Self as Bar<A>>::BarType> {
+    type BarType;
+}
+
+pub(crate) const B: usize = 5;
+
+pub trait Tec: Bar<B> {}
+
+pub struct Structure<C: Tec> { //~ ERROR the trait bound `C: Bar<5>` is not satisfied
+    _field: C::BarType, //~ ERROR the trait bound `C: Bar<5>` is not satisfied
+}
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr b/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr
new file mode 100644
index 00000000000..d87e769b505
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `C: Bar<5>` is not satisfied
+  --> $DIR/projections-in-super-trait-bound-unsatisfied.rs:16:1
+   |
+LL | pub struct Structure<C: Tec> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar<5>` is not implemented for `C`
+   |
+help: consider further restricting this bound
+   |
+LL | pub struct Structure<C: Tec + Bar<5>> {
+   |                             ++++++++
+
+error[E0277]: the trait bound `C: Bar<5>` is not satisfied
+  --> $DIR/projections-in-super-trait-bound-unsatisfied.rs:17:13
+   |
+LL |     _field: C::BarType,
+   |             ^^^^^^^^^^ the trait `Bar<5>` is not implemented for `C`
+   |
+help: consider further restricting this bound
+   |
+LL | pub struct Structure<C: Tec + Bar<5>> {
+   |                             ++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.rs b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.rs
new file mode 100644
index 00000000000..6c62415e06d
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.rs
@@ -0,0 +1,10 @@
+// We used to ICE here while trying to synthesize auto trait impls.
+// issue: 112828
+
+struct Outer(Inner);
+struct Inner;
+
+unsafe impl<Q: Trait> Send for Inner {}
+//~^ ERROR the type parameter `Q` is not constrained by the impl trait, self type, or predicates
+
+trait Trait {}
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr
new file mode 100644
index 00000000000..38d1a537fe4
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `Q` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/unconstrained-param-in-impl-ambiguity.rs:7:13
+   |
+LL | unsafe impl<Q: Trait> Send for Inner {}
+   |             ^ unconstrained type parameter
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/rustdoc/search-index-summaries.rs b/tests/rustdoc/search-index-summaries.rs
index efd366405bf..529b42d0ca9 100644
--- a/tests/rustdoc/search-index-summaries.rs
+++ b/tests/rustdoc/search-index-summaries.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// @hasraw 'search-index.js' 'Foo short link.'
+// @hasraw 'search.desc/foo/foo-desc-0-.js' 'Foo short link.'
 // @!hasraw - 'www.example.com'
 // @!hasraw - 'More Foo.'
 
diff --git a/tests/rustdoc/synthetic_auto/bounds.rs b/tests/rustdoc/synthetic_auto/bounds.rs
new file mode 100644
index 00000000000..17528d01c8d
--- /dev/null
+++ b/tests/rustdoc/synthetic_auto/bounds.rs
@@ -0,0 +1,21 @@
+pub struct Outer<T>(Inner<T>);
+pub struct Inner<T>(T);
+
+// @has bounds/struct.Outer.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
+// "impl<T> Unpin for Outer<T>where \
+//     T: for<'any> Trait<A = (), B<'any> = (), X = ()>,"
+
+impl<T> std::marker::Unpin for Inner<T>
+where
+    T: for<'any> Trait<A = (), B<'any> = (), X = ()>,
+{}
+
+pub trait Trait: SuperTrait {
+    type A;
+    type B<'a>;
+}
+
+pub trait SuperTrait {
+    type X;
+}
diff --git a/tests/rustdoc/synthetic_auto/complex.rs b/tests/rustdoc/synthetic_auto/complex.rs
index 4c39f0bf1e0..2722f6d338f 100644
--- a/tests/rustdoc/synthetic_auto/complex.rs
+++ b/tests/rustdoc/synthetic_auto/complex.rs
@@ -21,8 +21,8 @@ mod foo {
 
 // @has complex/struct.NotOuter.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
-// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \
-// -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
+// "impl<'a, T, K> Send for Outer<'a, T, K>where 'a: 'static, T: MyTrait<'a>, \
+// K: for<'b> Fn((&'b bool, &'a u8)) -> &'b i8 + ?Sized, <T as MyTrait<'a>>::MyItem: Copy,"
 
 pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter};
 
diff --git a/tests/rustdoc/synthetic_auto/lifetimes.rs b/tests/rustdoc/synthetic_auto/lifetimes.rs
index 71265b3078a..23e1efdaeef 100644
--- a/tests/rustdoc/synthetic_auto/lifetimes.rs
+++ b/tests/rustdoc/synthetic_auto/lifetimes.rs
@@ -10,7 +10,7 @@ where
 
 // @has lifetimes/struct.Foo.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
-// "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
+// "impl<'c, K> Send for Foo<'c, K>where 'c: 'static, K: for<'b> Fn(&'b bool) -> &'c u8,"
 //
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'c, K> Sync for Foo<'c, K>where K: Sync"
diff --git a/tests/rustdoc/synthetic_auto/no-redundancy.rs b/tests/rustdoc/synthetic_auto/no-redundancy.rs
index d30b38dd4dc..64dab429647 100644
--- a/tests/rustdoc/synthetic_auto/no-redundancy.rs
+++ b/tests/rustdoc/synthetic_auto/no-redundancy.rs
@@ -1,6 +1,3 @@
-// FIXME(fmease, #119216): Reenable this test!
-//@ ignore-test
-
 pub struct Inner<T> {
     field: T,
 }
@@ -13,7 +10,7 @@ where
 
 // @has no_redundancy/struct.Outer.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
-// "impl<T> Send for Outer<T>where T: Send + Copy"
+// "impl<T> Send for Outer<T>where T: Copy + Send"
 pub struct Outer<T> {
     inner_field: Inner<T>,
 }
diff --git a/tests/rustdoc/synthetic_auto/project.rs b/tests/rustdoc/synthetic_auto/project.rs
index 7c9412ae962..f4ede76e6de 100644
--- a/tests/rustdoc/synthetic_auto/project.rs
+++ b/tests/rustdoc/synthetic_auto/project.rs
@@ -24,11 +24,11 @@ where
 
 // @has project/struct.Foo.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
-// "impl<'c, K> Send for Foo<'c, K>where K: MyTrait<MyItem = bool>, 'c: 'static"
+// "impl<'c, K> Send for Foo<'c, K>where 'c: 'static, K: MyTrait<MyItem = bool>,"
 //
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
-// "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
-// 'c: 'static,"
+// "impl<'c, K> Sync for Foo<'c, K>where 'c: 'static, K: MyTrait, \
+// <K as MyTrait>::MyItem: OtherTrait,"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
 }
diff --git a/tests/ui-fulldeps/stable-mir/check_normalization.rs b/tests/ui-fulldeps/stable-mir/check_normalization.rs
new file mode 100644
index 00000000000..72e410f8080
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/check_normalization.rs
@@ -0,0 +1,95 @@
+//@ run-pass
+//! Test that types are normalized in an instance body.
+
+//@ ignore-stage1
+//@ ignore-cross-compile
+//@ ignore-remote
+//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
+//@ edition: 2021
+
+#![feature(rustc_private)]
+
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use mir::mono::Instance;
+use ty::{Ty, TyKind, RigidTy};
+use rustc_smir::rustc_internal;
+use stable_mir::*;
+use std::io::Write;
+use std::ops::ControlFlow;
+
+const CRATE_NAME: &str = "input";
+
+/// This function uses the Stable MIR APIs to get information about the test crate.
+fn test_stable_mir() -> ControlFlow<()> {
+    let items = stable_mir::all_local_items();
+
+    // Get all items and split generic vs monomorphic items.
+    let instances: Vec<_> =
+        items.into_iter().filter_map(|item| (!item.requires_monomorphization()).then(|| {
+            Instance::try_from(item).unwrap()
+        })).collect();
+    assert_eq!(instances.len(), 1, "Expected one constant");
+
+    for instance in instances {
+        check_ty(instance.ty());
+    }
+    ControlFlow::Continue(())
+}
+
+fn check_ty(ty: Ty) {
+    match ty.kind() {
+        TyKind::RigidTy(RigidTy::Adt(def, args)) if def.kind().is_struct() => {
+            // Ensure field type is also normalized
+            def.variants_iter().next().unwrap().fields().into_iter().for_each(|f| {
+                check_ty(f.ty_with_args(&args))
+            });
+        }
+        TyKind::RigidTy(RigidTy::Uint(..)) => {}
+        kind => unreachable!("Unexpected kind: {kind:?}")
+    }
+}
+
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "normalization_input.rs";
+    generate_input(&path).unwrap();
+    let args = vec![
+        "rustc".to_string(),
+        "-Cpanic=abort".to_string(),
+        "--crate-type=lib".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, test_stable_mir).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        pub trait Primitive {{
+            type Base;
+        }}
+
+        impl Primitive for char {{
+            type Base = u32;
+        }}
+
+        pub struct Wrapper<T: Primitive>(T::Base);
+        pub type WrapperChar = Wrapper<char>;
+        pub const NULL_CHAR: WrapperChar = Wrapper::<char>(0);
+        "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/abi/extern/extern-pass-FiveU16s.rs b/tests/ui/abi/extern/extern-pass-FiveU16s.rs
new file mode 100644
index 00000000000..5f1307beb28
--- /dev/null
+++ b/tests/ui/abi/extern/extern-pass-FiveU16s.rs
@@ -0,0 +1,30 @@
+//@ run-pass
+#![allow(improper_ctypes)]
+
+// Test a foreign function that accepts and returns a struct by value.
+
+// FiveU16s in particular is interesting because it is larger than a single 64 bit or 32 bit
+// register, which are used as cast destinations on some targets, but does not evenly divide those
+// sizes, causing there to be padding in the last element.
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct FiveU16s {
+    one: u16,
+    two: u16,
+    three: u16,
+    four: u16,
+    five: u16,
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    pub fn rust_dbg_extern_identity_FiveU16s(v: FiveU16s) -> FiveU16s;
+}
+
+pub fn main() {
+    unsafe {
+        let x = FiveU16s { one: 22, two: 23, three: 24, four: 25, five: 26 };
+        let y = rust_dbg_extern_identity_FiveU16s(x);
+        assert_eq!(x, y);
+    }
+}
diff --git a/tests/ui/abi/extern/extern-return-FiveU16s.rs b/tests/ui/abi/extern/extern-return-FiveU16s.rs
new file mode 100644
index 00000000000..d8ae8b2661c
--- /dev/null
+++ b/tests/ui/abi/extern/extern-return-FiveU16s.rs
@@ -0,0 +1,26 @@
+//@ run-pass
+#![allow(improper_ctypes)]
+
+pub struct FiveU16s {
+    one: u16,
+    two: u16,
+    three: u16,
+    four: u16,
+    five: u16,
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    pub fn rust_dbg_extern_return_FiveU16s() -> FiveU16s;
+}
+
+pub fn main() {
+    unsafe {
+        let y = rust_dbg_extern_return_FiveU16s();
+        assert_eq!(y.one, 10);
+        assert_eq!(y.two, 20);
+        assert_eq!(y.three, 30);
+        assert_eq!(y.four, 40);
+        assert_eq!(y.five, 50);
+    }
+}
diff --git a/tests/ui/asm/x86_64/goto.rs b/tests/ui/asm/x86_64/goto.rs
index 6a567efbb2c..6c14bb57ac6 100644
--- a/tests/ui/asm/x86_64/goto.rs
+++ b/tests/ui/asm/x86_64/goto.rs
@@ -1,8 +1,6 @@
 //@ only-x86_64
 //@ run-pass
 //@ needs-asm-support
-//@ revisions: mirunsafeck thirunsafeck
-//@ [thirunsafeck]compile-flags: -Z thir-unsafeck
 
 #![deny(unreachable_code)]
 #![feature(asm_goto)]
diff --git a/tests/ui/asm/x86_64/goto.mirunsafeck.stderr b/tests/ui/asm/x86_64/goto.stderr
index fe189c14f0a..27e227d71a5 100644
--- a/tests/ui/asm/x86_64/goto.mirunsafeck.stderr
+++ b/tests/ui/asm/x86_64/goto.stderr
@@ -1,5 +1,5 @@
 warning: unreachable statement
-  --> $DIR/goto.rs:99:9
+  --> $DIR/goto.rs:97:9
    |
 LL | /         asm!(
 LL | |             "jmp {}",
@@ -13,7 +13,7 @@ LL |           unreachable!();
    |           ^^^^^^^^^^^^^^ unreachable statement
    |
 note: the lint level is defined here
-  --> $DIR/goto.rs:89:8
+  --> $DIR/goto.rs:87:8
    |
 LL | #[warn(unreachable_code)]
    |        ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/asm/x86_64/goto.thirunsafeck.stderr b/tests/ui/asm/x86_64/goto.thirunsafeck.stderr
deleted file mode 100644
index fe189c14f0a..00000000000
--- a/tests/ui/asm/x86_64/goto.thirunsafeck.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-warning: unreachable statement
-  --> $DIR/goto.rs:99:9
-   |
-LL | /         asm!(
-LL | |             "jmp {}",
-LL | |             label {
-LL | |                 return;
-LL | |             },
-LL | |             options(noreturn)
-LL | |         );
-   | |_________- any code following this expression is unreachable
-LL |           unreachable!();
-   |           ^^^^^^^^^^^^^^ unreachable statement
-   |
-note: the lint level is defined here
-  --> $DIR/goto.rs:89:8
-   |
-LL | #[warn(unreachable_code)]
-   |        ^^^^^^^^^^^^^^^^
-   = note: this warning originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/async-await/async-closures/captures.rs b/tests/ui/async-await/async-closures/captures.rs
new file mode 100644
index 00000000000..e3ab8713709
--- /dev/null
+++ b/tests/ui/async-await/async-closures/captures.rs
@@ -0,0 +1,82 @@
+//@ aux-build:block-on.rs
+//@ edition:2021
+//@ run-pass
+//@ check-run-results
+
+// Same as miri's `tests/pass/async-closure-captures.rs`, keep in sync
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+fn main() {
+    block_on::block_on(async_main());
+}
+
+async fn call<T>(f: &impl async Fn() -> T) -> T {
+    f().await
+}
+
+async fn call_once<T>(f: impl async FnOnce() -> T) -> T {
+    f().await
+}
+
+#[derive(Debug)]
+#[allow(unused)]
+struct Hello(i32);
+
+async fn async_main() {
+    // Capture something by-ref
+    {
+        let x = Hello(0);
+        let c = async || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+
+        let x = &Hello(1);
+        let c = async || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+    }
+
+    // Capture something and consume it (force to `AsyncFnOnce`)
+    {
+        let x = Hello(2);
+        let c = async || {
+            println!("{x:?}");
+            drop(x);
+        };
+        call_once(c).await;
+    }
+
+    // Capture something with `move`, don't consume it
+    {
+        let x = Hello(3);
+        let c = async move || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+
+        let x = &Hello(4);
+        let c = async move || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+    }
+
+    // Capture something with `move`, also consume it (so `AsyncFnOnce`)
+    {
+        let x = Hello(5);
+        let c = async move || {
+            println!("{x:?}");
+            drop(x);
+        };
+        call_once(c).await;
+    }
+}
diff --git a/tests/ui/async-await/async-closures/captures.run.stdout b/tests/ui/async-await/async-closures/captures.run.stdout
new file mode 100644
index 00000000000..a0db6d236fe
--- /dev/null
+++ b/tests/ui/async-await/async-closures/captures.run.stdout
@@ -0,0 +1,10 @@
+Hello(0)
+Hello(0)
+Hello(1)
+Hello(1)
+Hello(2)
+Hello(3)
+Hello(3)
+Hello(4)
+Hello(4)
+Hello(5)
diff --git a/tests/ui/async-await/async-is-unwindsafe.rs b/tests/ui/async-await/async-is-unwindsafe.rs
index 53009b6e741..d0202f72f00 100644
--- a/tests/ui/async-await/async-is-unwindsafe.rs
+++ b/tests/ui/async-await/async-is-unwindsafe.rs
@@ -11,6 +11,7 @@ fn main() {
 
     is_unwindsafe(async {
         //~^ ERROR the type `&mut Context<'_>` may not be safely transferred across an unwind boundary
+        //~| ERROR the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
         use std::ptr::null;
         use std::task::{Context, RawWaker, RawWakerVTable, Waker};
         let waker = unsafe {
diff --git a/tests/ui/async-await/async-is-unwindsafe.stderr b/tests/ui/async-await/async-is-unwindsafe.stderr
index 5d87fc74768..6bb06df9f39 100644
--- a/tests/ui/async-await/async-is-unwindsafe.stderr
+++ b/tests/ui/async-await/async-is-unwindsafe.stderr
@@ -6,19 +6,18 @@ LL |        is_unwindsafe(async {
    |  |_____|
    | ||
 LL | ||
+LL | ||
 LL | ||         use std::ptr::null;
-LL | ||         use std::task::{Context, RawWaker, RawWakerVTable, Waker};
 ...  ||
 LL | ||         drop(cx_ref);
 LL | ||     });
    | ||_____-^ `&mut Context<'_>` may not be safely transferred across an unwind boundary
    |  |_____|
-   |        within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`
+   |        within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`
    |
-   = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}: UnwindSafe`
-   = note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>`
+   = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}: UnwindSafe`
 note: future does not implement `UnwindSafe` as this value is used across an await
-  --> $DIR/async-is-unwindsafe.rs:25:18
+  --> $DIR/async-is-unwindsafe.rs:26:18
    |
 LL |         let cx_ref = &mut cx;
    |             ------ has type `&mut Context<'_>` which does not implement `UnwindSafe`
@@ -31,6 +30,38 @@ note: required by a bound in `is_unwindsafe`
 LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
    |                          ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
 
-error: aborting due to 1 previous error
+error[E0277]: the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
+  --> $DIR/async-is-unwindsafe.rs:12:5
+   |
+LL |        is_unwindsafe(async {
+   |   _____^_____________-
+   |  |_____|
+   | ||
+LL | ||
+LL | ||
+LL | ||         use std::ptr::null;
+...  ||
+LL | ||         drop(cx_ref);
+LL | ||     });
+   | ||_____-^ `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
+   |  |_____|
+   |        within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`
+   |
+   = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`, the trait `UnwindSafe` is not implemented for `&mut (dyn Any + 'static)`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}: UnwindSafe`
+note: future does not implement `UnwindSafe` as this value is used across an await
+  --> $DIR/async-is-unwindsafe.rs:26:18
+   |
+LL |         let mut cx = Context::from_waker(&waker);
+   |             ------ has type `Context<'_>` which does not implement `UnwindSafe`
+...
+LL |         async {}.await; // this needs an inner await point
+   |                  ^^^^^ await occurs here, with `mut cx` maybe used later
+note: required by a bound in `is_unwindsafe`
+  --> $DIR/async-is-unwindsafe.rs:3:26
+   |
+LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
+   |                          ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr
index e4cb0915a10..1f1e303ea4c 100644
--- a/tests/ui/async-await/coroutine-desc.stderr
+++ b/tests/ui/async-await/coroutine-desc.stderr
@@ -5,6 +5,7 @@ LL |     fun(async {}, async {});
    |     --- --------  ^^^^^^^^ expected `async` block, found a different `async` block
    |     |   |
    |     |   the expected `async` block
+   |     |   expected all arguments to be this `async` block type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:17}`
@@ -13,14 +14,18 @@ note: function defined here
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the `async` block type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the `async` block type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error[E0308]: mismatched types
   --> $DIR/coroutine-desc.rs:12:16
    |
 LL |     fun(one(), two());
-   |     ---        ^^^^^ expected future, found a different future
-   |     |
+   |     --- -----  ^^^^^ expected future, found a different future
+   |     |   |
+   |     |   expected all arguments to be this future type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = help: consider `await`ing on both `Future`s
@@ -29,15 +34,19 @@ note: function defined here
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the future type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the future type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error[E0308]: mismatched types
   --> $DIR/coroutine-desc.rs:14:26
    |
 LL |     fun((async || {})(), (async || {})());
-   |     ---           --     ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
-   |     |             |
-   |     |             the expected `async` closure body
+   |     --- ---------------  ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
+   |     |   |         |
+   |     |   |         the expected `async` closure body
+   |     |   expected all arguments to be this `async` closure body type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:19: 14:21}`
@@ -46,7 +55,10 @@ note: function defined here
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the `async` closure body type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the `async` closure body type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs
new file mode 100644
index 00000000000..117f6134b4e
--- /dev/null
+++ b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs
@@ -0,0 +1,34 @@
+// It is UB to unwind out of `fn start()` according to
+// https://doc.rust-lang.org/beta/unstable-book/language-features/start.html so
+// panic with abort to avoid UB:
+//@ compile-flags: -Cpanic=abort
+//@ no-prefer-dynamic so panic=abort works
+
+#![feature(start, rustc_private)]
+
+extern crate libc;
+
+// Use #[start] so we don't have a runtime that messes with SIGPIPE.
+#[start]
+fn start(argc: isize, argv: *const *const u8) -> isize {
+    assert_eq!(argc, 2, "Must pass SIG_IGN or SIG_DFL as first arg");
+    let arg1 = unsafe { std::ffi::CStr::from_ptr(*argv.offset(1) as *const libc::c_char) }
+        .to_str()
+        .unwrap();
+
+    let expected = match arg1 {
+        "SIG_IGN" => libc::SIG_IGN,
+        "SIG_DFL" => libc::SIG_DFL,
+        arg => panic!("Must pass SIG_IGN or SIG_DFL as first arg. Got: {}", arg),
+    };
+
+    let actual = unsafe {
+        let mut actual: libc::sigaction = std::mem::zeroed();
+        libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual);
+        actual.sa_sigaction
+    };
+
+    assert_eq!(actual, expected, "actual and expected SIGPIPE disposition in child differs");
+
+    0
+}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs
new file mode 100644
index 00000000000..f96bd634876
--- /dev/null
+++ b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs
@@ -0,0 +1,56 @@
+//@ revisions: default sig_dfl sig_ign inherit
+//@ ignore-cross-compile because aux-bin does not yet support it
+//@ only-unix because SIGPIPE is a unix thing
+//@ run-pass
+//@ aux-bin:assert-sigpipe-disposition.rs
+//@ aux-crate:sigpipe_utils=sigpipe-utils.rs
+
+// Checks the signal disposition of `SIGPIPE` in child processes, and in our own
+// process for robustness. Without any `unix_sigpipe` attribute, `SIG_IGN` is
+// the default. But there is a difference in how `SIGPIPE` is treated in child
+// processes with and without the attribute. Search for
+// `unix_sigpipe_attr_specified()` in the code base to learn more.
+
+#![feature(rustc_private)]
+#![cfg_attr(any(sig_dfl, sig_ign, inherit), feature(unix_sigpipe))]
+
+extern crate libc;
+extern crate sigpipe_utils;
+
+use sigpipe_utils::*;
+
+#[cfg_attr(sig_dfl, unix_sigpipe = "sig_dfl")]
+#[cfg_attr(sig_ign, unix_sigpipe = "sig_ign")]
+#[cfg_attr(inherit, unix_sigpipe = "inherit")]
+fn main() {
+    // By default we get SIG_IGN but the child gets SIG_DFL through an explicit
+    // reset before exec:
+    // https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L363-L384
+    #[cfg(default)]
+    let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_DFL");
+
+    // With #[unix_sigpipe = "sig_dfl"] we get SIG_DFL and the child does too
+    // without any special code running before exec.
+    #[cfg(sig_dfl)]
+    let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
+
+    // With #[unix_sigpipe = "sig_ign"] we get SIG_IGN and the child does too
+    // without any special code running before exec.
+    #[cfg(sig_ign)]
+    let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_IGN");
+
+    // With #[unix_sigpipe = "inherit"] we get SIG_DFL and the child does too
+    // without any special code running before exec.
+    #[cfg(inherit)]
+    let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
+
+    assert_sigpipe_handler(we_expect);
+
+    assert!(
+        std::process::Command::new("./auxiliary/bin/assert-sigpipe-disposition")
+            .arg(child_expects)
+            .status()
+            .unwrap()
+            .success()
+    );
+}
diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr
index 32bd2554abb..47af51e2106 100644
--- a/tests/ui/binop/binary-op-suggest-deref.stderr
+++ b/tests/ui/binop/binary-op-suggest-deref.stderr
@@ -247,15 +247,15 @@ LL |     _ = &&0 == Foo;
    |
    = help: the trait `PartialEq<Foo>` is not implemented for `&&{integer}`
    = help: the following other types implement trait `PartialEq<Rhs>`:
+             f128
+             f16
              f32
              f64
              i128
              i16
              i32
              i64
-             i8
-             isize
-           and 6 others
+           and 8 others
 
 error[E0369]: binary operation `==` cannot be applied to type `Foo`
   --> $DIR/binary-op-suggest-deref.rs:60:13
diff --git a/tests/ui/issues/issue-1460.rs b/tests/ui/closures/issue-1460.rs
index c201f026bca..c201f026bca 100644
--- a/tests/ui/issues/issue-1460.rs
+++ b/tests/ui/closures/issue-1460.rs
diff --git a/tests/ui/issues/issue-1460.stderr b/tests/ui/closures/issue-1460.stderr
index d4a8c8955e2..d4a8c8955e2 100644
--- a/tests/ui/issues/issue-1460.stderr
+++ b/tests/ui/closures/issue-1460.stderr
diff --git a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
index 498ef33d52e..46723c5a297 100644
--- a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
+++ b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
@@ -2,8 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18
    |
 LL |     test(&mut 7, &7);
-   |     ----         ^^ types differ in mutability
-   |     |
+   |     ---- ------  ^^ types differ in mutability
+   |     |    |
+   |     |    expected all arguments to be this `&mut {integer}` type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected mutable reference `&mut {integer}`
@@ -12,7 +13,10 @@ note: function defined here
   --> $DIR/coerce-reborrow-multi-arg-fail.rs:1:4
    |
 LL | fn test<T>(_a: T, _b: T) {}
-   |    ^^^^           -----
+   |    ^^^^ -  -----  ----- this parameter needs to match the `&mut {integer}` type of `_a`
+   |         |  |
+   |         |  `_b` needs to match the `&mut {integer}` type of this parameter
+   |         `_a` and `_b` all reference this parameter T
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.rs b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs
new file mode 100644
index 00000000000..6c2a11e0135
--- /dev/null
+++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs
@@ -0,0 +1,23 @@
+//@ check-pass
+
+#![feature(adt_const_params)]
+//~^ WARN the feature `adt_const_params` is incomplete
+#![feature(with_negative_coherence, negative_impls)]
+
+pub trait A<const K: &'static str> {}
+pub trait C {}
+
+
+struct W<T>(T);
+
+// Negative coherence:
+// Proving `W<!T>: !A<"">` requires proving `CONST alias-eq ""`, which requires proving
+// `CONST normalizes-to (?1c: &str)`. The type's region is uniquified, so it ends up being
+// put in to the canonical vars list with an infer region => ICE.
+impl<T> C for T where T: A<""> {}
+impl<T> C for W<T> {}
+
+impl<T> !A<CONST> for W<T> {}
+const CONST: &str = "";
+
+fn main() {}
diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr
new file mode 100644
index 00000000000..dc8c926f182
--- /dev/null
+++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr
@@ -0,0 +1,11 @@
+warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/regions-in-canonical.rs:3:12
+   |
+LL | #![feature(adt_const_params)]
+   |            ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/compiletest-self-test/test-aux-bin.rs b/tests/ui/compiletest-self-test/test-aux-bin.rs
index 9e01e3ffabf..c1c28e12b3b 100644
--- a/tests/ui/compiletest-self-test/test-aux-bin.rs
+++ b/tests/ui/compiletest-self-test/test-aux-bin.rs
@@ -1,4 +1,4 @@
-//@ ignore-cross-compile because we run the compiled code
+//@ ignore-cross-compile because aux-bin does not yet support it
 //@ aux-bin: print-it-works.rs
 //@ run-pass
 
diff --git a/tests/ui/consts/const-eval/parse_ints.rs b/tests/ui/consts/const-eval/parse_ints.rs
new file mode 100644
index 00000000000..ff9fc47e65c
--- /dev/null
+++ b/tests/ui/consts/const-eval/parse_ints.rs
@@ -0,0 +1,10 @@
+#![feature(const_int_from_str)]
+
+const _OK: () = match i32::from_str_radix("-1234", 10) {
+    Ok(x) => assert!(x == -1234),
+    Err(_) => panic!(),
+};
+const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); };
+const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); };
+
+fn main () {}
diff --git a/tests/ui/consts/const-eval/parse_ints.stderr b/tests/ui/consts/const-eval/parse_ints.stderr
new file mode 100644
index 00000000000..9e49fe433a1
--- /dev/null
+++ b/tests/ui/consts/const-eval/parse_ints.stderr
@@ -0,0 +1,31 @@
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/num/mod.rs:LL:COL
+   |
+   = note: the evaluated program panicked at 'from_str_radix_int: must lie in the range `[2, 36]`', $SRC_DIR/core/src/num/mod.rs:LL:COL
+   |
+note: inside `core::num::<impl u64>::from_str_radix`
+  --> $SRC_DIR/core/src/num/mod.rs:LL:COL
+note: inside `_TOO_LOW`
+  --> $DIR/parse_ints.rs:7:24
+   |
+LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); };
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `from_str_radix` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/num/mod.rs:LL:COL
+   |
+   = note: the evaluated program panicked at 'from_str_radix_int: must lie in the range `[2, 36]`', $SRC_DIR/core/src/num/mod.rs:LL:COL
+   |
+note: inside `core::num::<impl u64>::from_str_radix`
+  --> $SRC_DIR/core/src/num/mod.rs:LL:COL
+note: inside `_TOO_HIGH`
+  --> $DIR/parse_ints.rs:8:25
+   |
+LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); };
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `from_str_radix` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr
deleted file mode 100644
index 34ec8aadbcf..00000000000
--- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:12:5
-   |
-LL |     foo();
-   |     ^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:9:17
-   |
-LL |     let a: [u8; foo()];
-   |                 ^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
deleted file mode 100644
index e6b8173eb05..00000000000
--- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:12:5
-   |
-LL |     foo();
-   |     ^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:9:17
-   |
-LL |     let a: [u8; foo()];
-   |                 ^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/consts/const-int-unchecked.rs b/tests/ui/consts/const-int-unchecked.rs
index 902a668488b..8de28aa2bb1 100644
--- a/tests/ui/consts/const-int-unchecked.rs
+++ b/tests/ui/consts/const-int-unchecked.rs
@@ -1,5 +1,5 @@
 #![feature(core_intrinsics)]
-#![feature(const_int_unchecked_arith)]
+
 
 use std::intrinsics;
 
@@ -27,7 +27,7 @@ const SHL_U128: u128 = unsafe { intrinsics::unchecked_shl(5_u128, 128) };
 
 const SHL_I8: i8 = unsafe { intrinsics::unchecked_shl(5_i8, 8) };
 //~^ ERROR evaluation of constant value failed
-const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_16, 16) };
+const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_i16, 16) };
 //~^ ERROR evaluation of constant value failed
 const SHL_I32: i32 = unsafe { intrinsics::unchecked_shl(5_i32, 32) };
 //~^ ERROR evaluation of constant value failed
@@ -40,7 +40,7 @@ const SHL_I128: i128 = unsafe { intrinsics::unchecked_shl(5_i128, 128) };
 
 const SHL_I8_NEG: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -1) };
 //~^ ERROR evaluation of constant value failed
-const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_16, -1) };
+const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -1) };
 //~^ ERROR evaluation of constant value failed
 const SHL_I32_NEG: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -1) };
 //~^ ERROR evaluation of constant value failed
@@ -54,7 +54,7 @@ const SHL_I128_NEG: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -1) };
 
 const SHL_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -6) };
 //~^ ERROR evaluation of constant value failed
-const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_16, -13) };
+const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -13) };
 //~^ ERROR evaluation of constant value failed
 const SHL_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -25) };
 //~^ ERROR evaluation of constant value failed
@@ -82,7 +82,7 @@ const SHR_U128: u128 = unsafe { intrinsics::unchecked_shr(5_u128, 128) };
 
 const SHR_I8: i8 = unsafe { intrinsics::unchecked_shr(5_i8, 8) };
 //~^ ERROR evaluation of constant value failed
-const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_16, 16) };
+const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_i16, 16) };
 //~^ ERROR evaluation of constant value failed
 const SHR_I32: i32 = unsafe { intrinsics::unchecked_shr(5_i32, 32) };
 //~^ ERROR evaluation of constant value failed
@@ -95,7 +95,7 @@ const SHR_I128: i128 = unsafe { intrinsics::unchecked_shr(5_i128, 128) };
 
 const SHR_I8_NEG: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -1) };
 //~^ ERROR evaluation of constant value failed
-const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_16, -1) };
+const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -1) };
 //~^ ERROR evaluation of constant value failed
 const SHR_I32_NEG: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -1) };
 //~^ ERROR evaluation of constant value failed
@@ -109,7 +109,7 @@ const SHR_I128_NEG: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -1) };
 
 const SHR_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -6) };
 //~^ ERROR evaluation of constant value failed
-const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_16, -13) };
+const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -13) };
 //~^ ERROR evaluation of constant value failed
 const SHR_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -25) };
 //~^ ERROR evaluation of constant value failed
diff --git a/tests/ui/consts/const-int-unchecked.stderr b/tests/ui/consts/const-int-unchecked.stderr
index ad14c8f68f8..84b222972a1 100644
--- a/tests/ui/consts/const-int-unchecked.stderr
+++ b/tests/ui/consts/const-int-unchecked.stderr
@@ -37,8 +37,8 @@ LL | const SHL_I8: i8 = unsafe { intrinsics::unchecked_shl(5_i8, 8) };
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:30:31
    |
-LL | const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_16, 16) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shl`
+LL | const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_i16, 16) };
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shl`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:32:31
@@ -67,8 +67,8 @@ LL | const SHL_I8_NEG: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -1) };
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:43:35
    |
-LL | const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_16, -1) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shl`
+LL | const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -1) };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shl`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:45:35
@@ -97,8 +97,8 @@ LL | const SHL_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -6)
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:57:42
    |
-LL | const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_16, -13) };
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -13 in `unchecked_shl`
+LL | const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -13) };
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -13 in `unchecked_shl`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:59:42
@@ -157,8 +157,8 @@ LL | const SHR_I8: i8 = unsafe { intrinsics::unchecked_shr(5_i8, 8) };
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:85:31
    |
-LL | const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_16, 16) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shr`
+LL | const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_i16, 16) };
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shr`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:87:31
@@ -187,8 +187,8 @@ LL | const SHR_I8_NEG: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -1) };
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:98:35
    |
-LL | const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_16, -1) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shr`
+LL | const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -1) };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shr`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:100:35
@@ -217,8 +217,8 @@ LL | const SHR_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -6)
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:112:42
    |
-LL | const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_16, -13) };
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -13 in `unchecked_shr`
+LL | const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -13) };
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -13 in `unchecked_shr`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:114:42
diff --git a/tests/ui/derives/auxiliary/rustc-serialize.rs b/tests/ui/derives/auxiliary/rustc-serialize.rs
new file mode 100644
index 00000000000..24177af931c
--- /dev/null
+++ b/tests/ui/derives/auxiliary/rustc-serialize.rs
@@ -0,0 +1,16 @@
+#![crate_type = "lib"]
+
+pub trait Decoder {
+    type Error;
+
+    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error>
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F)
+                               -> Result<T, Self::Error>
+        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>;
+
+}
+
+pub trait Decodable: Sized {
+    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error>;
+}
diff --git a/tests/ui/derives/rustc-decodable-issue-123156.rs b/tests/ui/derives/rustc-decodable-issue-123156.rs
new file mode 100644
index 00000000000..1983837ed8d
--- /dev/null
+++ b/tests/ui/derives/rustc-decodable-issue-123156.rs
@@ -0,0 +1,11 @@
+//@ check-pass
+//@ edition:2021
+//@ aux-build:rustc-serialize.rs
+
+#![crate_type = "lib"]
+#![allow(deprecated, soft_unstable)]
+
+extern crate rustc_serialize;
+
+#[derive(RustcDecodable)]
+pub enum Foo {}
diff --git a/tests/ui/derives/rustc-decodable-issue-123156.stderr b/tests/ui/derives/rustc-decodable-issue-123156.stderr
new file mode 100644
index 00000000000..ee7b33d59bb
--- /dev/null
+++ b/tests/ui/derives/rustc-decodable-issue-123156.stderr
@@ -0,0 +1,10 @@
+Future incompatibility report: Future breakage diagnostic:
+warning: use of unstable library feature 'rustc_encodable_decodable': derive macro for `rustc-serialize`; should not be used in new code
+  --> $DIR/rustc-decodable-issue-123156.rs:10:10
+   |
+LL | #[derive(RustcDecodable)]
+   |          ^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266>
+
diff --git a/tests/ui/feature-gates/feature-gate-f128.stderr b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr
index 299375c9aed..771aee79dce 100644
--- a/tests/ui/feature-gates/feature-gate-f128.stderr
+++ b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:3:10
+  --> $DIR/feature-gate-f128.rs:7:10
    |
 LL | const A: f128 = 10.0;
    |          ^^^^
@@ -9,7 +9,7 @@ LL | const A: f128 = 10.0;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:6:12
+  --> $DIR/feature-gate-f128.rs:10:12
    |
 LL |     let a: f128 = 100.0;
    |            ^^^^
@@ -19,7 +19,7 @@ LL |     let a: f128 = 100.0;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:11:11
+  --> $DIR/feature-gate-f128.rs:15:11
    |
 LL | fn foo(a: f128) {}
    |           ^^^^
@@ -29,7 +29,7 @@ LL | fn foo(a: f128) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:14:8
+  --> $DIR/feature-gate-f128.rs:18:8
    |
 LL |     a: f128,
    |        ^^^^
@@ -39,7 +39,7 @@ LL |     a: f128,
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:7:13
+  --> $DIR/feature-gate-f128.rs:11:13
    |
 LL |     let b = 0.0f128;
    |             ^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr
new file mode 100644
index 00000000000..771aee79dce
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr
@@ -0,0 +1,53 @@
+error[E0658]: the type `f128` is unstable
+  --> $DIR/feature-gate-f128.rs:7:10
+   |
+LL | const A: f128 = 10.0;
+   |          ^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f128)]` 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]: the type `f128` is unstable
+  --> $DIR/feature-gate-f128.rs:10:12
+   |
+LL |     let a: f128 = 100.0;
+   |            ^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f128)]` 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]: the type `f128` is unstable
+  --> $DIR/feature-gate-f128.rs:15:11
+   |
+LL | fn foo(a: f128) {}
+   |           ^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f128)]` 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]: the type `f128` is unstable
+  --> $DIR/feature-gate-f128.rs:18:8
+   |
+LL |     a: f128,
+   |        ^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f128)]` 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]: the type `f128` is unstable
+  --> $DIR/feature-gate-f128.rs:11:13
+   |
+LL |     let b = 0.0f128;
+   |             ^^^^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f128)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-f128.rs b/tests/ui/feature-gates/feature-gate-f128.rs
index 7f60fb6afa0..d25b6dde4ee 100644
--- a/tests/ui/feature-gates/feature-gate-f128.rs
+++ b/tests/ui/feature-gates/feature-gate-f128.rs
@@ -1,3 +1,7 @@
+//@ revisions: e2015 e2018
+//
+//@[e2018] edition:2018
+
 #![allow(unused)]
 
 const A: f128 = 10.0; //~ ERROR the type `f128` is unstable
diff --git a/tests/ui/feature-gates/feature-gate-f16.stderr b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr
index e54b54a47bd..2bb3b59465a 100644
--- a/tests/ui/feature-gates/feature-gate-f16.stderr
+++ b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:3:10
+  --> $DIR/feature-gate-f16.rs:7:10
    |
 LL | const A: f16 = 10.0;
    |          ^^^
@@ -9,7 +9,7 @@ LL | const A: f16 = 10.0;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:6:12
+  --> $DIR/feature-gate-f16.rs:10:12
    |
 LL |     let a: f16 = 100.0;
    |            ^^^
@@ -19,7 +19,7 @@ LL |     let a: f16 = 100.0;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:11:11
+  --> $DIR/feature-gate-f16.rs:15:11
    |
 LL | fn foo(a: f16) {}
    |           ^^^
@@ -29,7 +29,7 @@ LL | fn foo(a: f16) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:14:8
+  --> $DIR/feature-gate-f16.rs:18:8
    |
 LL |     a: f16,
    |        ^^^
@@ -39,7 +39,7 @@ LL |     a: f16,
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:7:13
+  --> $DIR/feature-gate-f16.rs:11:13
    |
 LL |     let b = 0.0f16;
    |             ^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-f16.e2018.stderr b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr
new file mode 100644
index 00000000000..2bb3b59465a
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr
@@ -0,0 +1,53 @@
+error[E0658]: the type `f16` is unstable
+  --> $DIR/feature-gate-f16.rs:7:10
+   |
+LL | const A: f16 = 10.0;
+   |          ^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f16)]` 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]: the type `f16` is unstable
+  --> $DIR/feature-gate-f16.rs:10:12
+   |
+LL |     let a: f16 = 100.0;
+   |            ^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f16)]` 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]: the type `f16` is unstable
+  --> $DIR/feature-gate-f16.rs:15:11
+   |
+LL | fn foo(a: f16) {}
+   |           ^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f16)]` 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]: the type `f16` is unstable
+  --> $DIR/feature-gate-f16.rs:18:8
+   |
+LL |     a: f16,
+   |        ^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f16)]` 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]: the type `f16` is unstable
+  --> $DIR/feature-gate-f16.rs:11:13
+   |
+LL |     let b = 0.0f16;
+   |             ^^^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f16)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-f16.rs b/tests/ui/feature-gates/feature-gate-f16.rs
index 31d8f87f3ba..af906d71f5f 100644
--- a/tests/ui/feature-gates/feature-gate-f16.rs
+++ b/tests/ui/feature-gates/feature-gate-f16.rs
@@ -1,3 +1,7 @@
+//@ revisions: e2015 e2018
+//
+//@[e2018] edition:2018
+
 #![allow(unused)]
 
 const A: f16 = 10.0; //~ ERROR the type `f16` is unstable
diff --git a/tests/ui/fn/fn-item-lifetime-bounds.rs b/tests/ui/fn/fn-item-lifetime-bounds.rs
deleted file mode 100644
index b80b7eade23..00000000000
--- a/tests/ui/fn/fn-item-lifetime-bounds.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-//@ check-pass
-//@ known-bug: #84533
-
-// Should fail. Lifetimes are checked correctly when `foo` is called, but NOT
-// when only the lifetime parameters are instantiated.
-
-use std::marker::PhantomData;
-
-#[allow(dead_code)]
-fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> {
-    PhantomData
-}
-
-#[allow(dead_code)]
-#[allow(path_statements)]
-fn caller<'b, 'a>() {
-    foo::<'b, 'a>;
-}
-
-// In contrast to above, below code correctly does NOT compile.
-// fn caller<'b, 'a>() {
-//     foo::<'b, 'a>();
-// }
-
-// error: lifetime may not live long enough
-//   --> src/main.rs:22:5
-//   |
-// 21 | fn caller<'b, 'a>() {
-//   |           --  -- lifetime `'a` defined here
-//   |           |
-//   |           lifetime `'b` defined here
-// 22 |     foo::<'b, 'a>();
-//   |     ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
-//   |
-//   = help: consider adding the following bound: `'a: 'b`
-
-fn main() {}
diff --git a/tests/ui/fn/fn-item-type.stderr b/tests/ui/fn/fn-item-type.stderr
index da90b8b81c8..76cdbcceac8 100644
--- a/tests/ui/fn/fn-item-type.stderr
+++ b/tests/ui/fn/fn-item-type.stderr
@@ -2,8 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:22:19
    |
 LL |     eq(foo::<u8>, bar::<u8>);
-   |     --            ^^^^^^^^^ expected fn item, found a different fn item
-   |     |
+   |     -- ---------  ^^^^^^^^^ expected fn item, found a different fn item
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -13,15 +14,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:29:19
    |
 LL |     eq(foo::<u8>, foo::<i8>);
-   |     --            ^^^^^^^^^ expected `u8`, found `i8`
-   |     |
+   |     -- ---------  ^^^^^^^^^ expected `u8`, found `i8`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -31,15 +36,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:34:23
    |
 LL |     eq(bar::<String>, bar::<Vec<u8>>);
-   |     --                ^^^^^^^^^^^^^^ expected `String`, found `Vec<u8>`
-   |     |
+   |     -- -------------  ^^^^^^^^^^^^^^ expected `String`, found `Vec<u8>`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {bar::<String>}`
@@ -49,15 +58,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:40:26
    |
 LL |     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
-   |     --                   ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
-   |     |
+   |     -- ----------------  ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn() {<u8 as Foo>::foo}`
@@ -67,15 +80,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn()`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:45:19
    |
 LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
-   |     --            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
-   |     |
+   |     -- ---------  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -85,7 +102,10 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/issues/issue-1451.rs b/tests/ui/fn/issue-1451.rs
index 735b766bd0c..735b766bd0c 100644
--- a/tests/ui/issues/issue-1451.rs
+++ b/tests/ui/fn/issue-1451.rs
diff --git a/tests/ui/issues/issue-1900.rs b/tests/ui/fn/issue-1900.rs
index 761bd317027..761bd317027 100644
--- a/tests/ui/issues/issue-1900.rs
+++ b/tests/ui/fn/issue-1900.rs
diff --git a/tests/ui/issues/issue-1900.stderr b/tests/ui/fn/issue-1900.stderr
index 31fd46c8e2a..31fd46c8e2a 100644
--- a/tests/ui/issues/issue-1900.stderr
+++ b/tests/ui/fn/issue-1900.stderr
diff --git a/tests/ui/higher-ranked/builtin-closure-like-bounds.rs b/tests/ui/higher-ranked/builtin-closure-like-bounds.rs
new file mode 100644
index 00000000000..dee290cc439
--- /dev/null
+++ b/tests/ui/higher-ranked/builtin-closure-like-bounds.rs
@@ -0,0 +1,58 @@
+//@ edition:2024
+//@ compile-flags: -Zunstable-options
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// Makes sure that we support closure/coroutine goals where the signature of
+// the item references higher-ranked lifetimes from the *predicate* binder,
+// not its own internal signature binder.
+//
+// This was fixed in <https://github.com/rust-lang/rust/pull/122267>.
+
+#![feature(unboxed_closures, gen_blocks)]
+
+trait Dispatch {
+    fn dispatch(self);
+}
+
+struct Fut<T>(T);
+impl<T: for<'a> Fn<(&'a (),)>> Dispatch for Fut<T>
+where
+    for<'a> <T as FnOnce<(&'a (),)>>::Output: Future,
+{
+    fn dispatch(self) {
+        (self.0)(&());
+    }
+}
+
+struct Gen<T>(T);
+impl<T: for<'a> Fn<(&'a (),)>> Dispatch for Gen<T>
+where
+    for<'a> <T as FnOnce<(&'a (),)>>::Output: Iterator,
+{
+    fn dispatch(self) {
+        (self.0)(&());
+    }
+}
+
+struct Closure<T>(T);
+impl<T: for<'a> Fn<(&'a (),)>> Dispatch for Closure<T>
+where
+    for<'a> <T as FnOnce<(&'a (),)>>::Output: Fn<(&'a (),)>,
+{
+    fn dispatch(self) {
+        (self.0)(&())(&());
+    }
+}
+
+fn main() {
+    async fn foo(_: &()) {}
+    Fut(foo).dispatch();
+
+    gen fn bar(_: &()) {}
+    Gen(bar).dispatch();
+
+    fn uwu<'a>(x: &'a ()) -> impl Fn(&'a ()) { |_| {} }
+    Closure(uwu).dispatch();
+}
diff --git a/tests/ui/higher-ranked/closure-bound-codegen-ice.rs b/tests/ui/higher-ranked/closure-bound-codegen-ice.rs
new file mode 100644
index 00000000000..4d7ae12d7a7
--- /dev/null
+++ b/tests/ui/higher-ranked/closure-bound-codegen-ice.rs
@@ -0,0 +1,33 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ build-pass
+
+// Regression test for incomplete handling of Fn-trait goals,
+// fixed in #122267.
+
+trait Trait {
+    type Assoc<'a>: FnOnce(&'a ());
+}
+
+impl Trait for () {
+    type Assoc<'a> = fn(&'a ());
+}
+
+trait Indir {
+    fn break_me() {}
+}
+
+impl<F: Trait> Indir for F
+where
+    for<'a> F::Assoc<'a>: FnOnce(&'a ()),
+{
+    fn break_me() {}
+}
+
+fn foo<F: Trait>() {
+    F::break_me()
+}
+
+fn main() {
+    foo::<()>();
+}
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs
new file mode 100644
index 00000000000..b448f0bdc77
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs
@@ -0,0 +1,28 @@
+// cc #119820
+
+trait Trait {}
+
+impl<T: Trait> Trait for &T {}
+impl Trait for u32 {}
+
+fn hr_bound<T>()
+where
+    for<'a> &'a T: Trait,
+{
+}
+
+fn foo<T>()
+where
+    T: Trait,
+    for<'a> &'a &'a T: Trait,
+{
+    // We get a universe error when using the `param_env` candidate
+    // but are able to successfully use the impl candidate. Without
+    // the leak check both candidates may apply and we prefer the
+    // `param_env` candidate in winnowing.
+    hr_bound::<&T>();
+    //~^ ERROR the parameter type `T` may not live long enough
+    //~| ERROR implementation of `Trait` is not general enough
+}
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr
new file mode 100644
index 00000000000..febe252d7d1
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr
@@ -0,0 +1,26 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/candidate-from-env-universe-err-1.rs:23:5
+   |
+LL |     hr_bound::<&T>();
+   |     ^^^^^^^^^^^^^^
+   |     |
+   |     the parameter type `T` must be valid for the static lifetime...
+   |     ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     T: Trait + 'static,
+   |              +++++++++
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/candidate-from-env-universe-err-1.rs:23:5
+   |
+LL |     hr_bound::<&T>();
+   |     ^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `Trait` would have to be implemented for the type `&'0 &T`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `&'1 &'1 T`, for some specific lifetime `'1`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr
new file mode 100644
index 00000000000..22ce87c0248
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr
@@ -0,0 +1,25 @@
+error: lifetime may not live long enough
+  --> $DIR/candidate-from-env-universe-err-2.rs:14:5
+   |
+LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
+   |           -- lifetime `'a` defined here
+LL |     impl_hr::<T>();
+   |     ^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/candidate-from-env-universe-err-2.rs:11:19
+   |
+LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/candidate-from-env-universe-err-2.rs:14:5
+   |
+LL |     impl_hr::<T>();
+   |     ^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `T` must implement `Trait<'0, '_>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Trait<'1, '_>`, for some specific lifetime `'1`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr
new file mode 100644
index 00000000000..a61bc748bea
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied
+  --> $DIR/candidate-from-env-universe-err-2.rs:14:5
+   |
+LL |     impl_hr::<T>();
+   |     ^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a, '_>` is not implemented for `T`
+   |
+note: required by a bound in `impl_hr`
+  --> $DIR/candidate-from-env-universe-err-2.rs:11:19
+   |
+LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impl_hr`
+help: consider further restricting this bound
+   |
+LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static> + for<'a> Trait<'a, '_>>() {
+   |                                                              +++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr
new file mode 100644
index 00000000000..29a72b1c1b6
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr
@@ -0,0 +1,26 @@
+error: lifetime may not live long enough
+  --> $DIR/candidate-from-env-universe-err-2.rs:14:5
+   |
+LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
+   |           -- lifetime `'a` defined here
+LL |     impl_hr::<T>();
+   |     ^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/candidate-from-env-universe-err-2.rs:11:19
+   |
+LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/candidate-from-env-universe-err-2.rs:14:5
+   |
+LL |     impl_hr::<T>();
+   |     ^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected trait `for<'a> Trait<'a, '_>`
+              found trait `for<'b> Trait<'_, 'b>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs
new file mode 100644
index 00000000000..56fa70469cc
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs
@@ -0,0 +1,20 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+
+// cc #119820
+
+trait Trait<'a, 'b> {}
+
+trait OtherTrait<'b> {}
+impl<'a, 'b, T: OtherTrait<'b>> Trait<'a, 'b> for T {}
+
+fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
+
+fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
+    impl_hr::<T>();
+    //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied
+    //[current]~^^ERROR lifetime may not live long enough
+    //[current]~| ERROR implementation of `Trait` is not general enough
+}
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr
new file mode 100644
index 00000000000..bb0b2de788e
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr
@@ -0,0 +1,54 @@
+error: implementation of `Trait` is not general enough
+  --> $DIR/candidate-from-env-universe-err-project.rs:28:5
+   |
+LL |     trait_bound::<T>();
+   |     ^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `T` must implement `Trait<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Trait<'static>`
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/candidate-from-env-universe-err-project.rs:39:5
+   |
+LL |     projection_bound::<T>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `T` must implement `Trait<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Trait<'static>`
+
+error[E0308]: mismatched types
+  --> $DIR/candidate-from-env-universe-err-project.rs:39:5
+   |
+LL |     projection_bound::<T>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected associated type `<T as Trait<'static>>::Assoc`
+              found associated type `<T as Trait<'a>>::Assoc`
+note: the lifetime requirement is introduced here
+  --> $DIR/candidate-from-env-universe-err-project.rs:18:42
+   |
+LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
+   |                                          ^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/candidate-from-env-universe-err-project.rs:55:30
+   |
+LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected associated type `<T as Trait<'static>>::Assoc`
+              found associated type `<T as Trait<'a>>::Assoc`
+
+error[E0308]: mismatched types
+  --> $DIR/candidate-from-env-universe-err-project.rs:55:30
+   |
+LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected associated type `<T as Trait<'static>>::Assoc`
+              found associated type `<T as Trait<'a>>::Assoc`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr
new file mode 100644
index 00000000000..2804d5bbe94
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr
@@ -0,0 +1,67 @@
+error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied
+  --> $DIR/candidate-from-env-universe-err-project.rs:28:19
+   |
+LL |     trait_bound::<T>();
+   |                   ^ the trait `for<'a> Trait<'a>` is not implemented for `T`
+   |
+note: required by a bound in `trait_bound`
+  --> $DIR/candidate-from-env-universe-err-project.rs:17:19
+   |
+LL | fn trait_bound<T: for<'a> Trait<'a>>() {}
+   |                   ^^^^^^^^^^^^^^^^^ required by this bound in `trait_bound`
+help: consider further restricting this bound
+   |
+LL | fn function1<T: Trait<'static> + for<'a> Trait<'a>>() {
+   |                                +++++++++++++++++++
+
+error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied
+  --> $DIR/candidate-from-env-universe-err-project.rs:39:24
+   |
+LL |     projection_bound::<T>();
+   |                        ^ the trait `for<'a> Trait<'a>` is not implemented for `T`
+   |
+note: required by a bound in `projection_bound`
+  --> $DIR/candidate-from-env-universe-err-project.rs:18:24
+   |
+LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound`
+help: consider further restricting this bound
+   |
+LL | fn function2<T: Trait<'static, Assoc = usize> + for<'a> Trait<'a>>() {
+   |                                               +++++++++++++++++++
+
+error[E0271]: type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
+  --> $DIR/candidate-from-env-universe-err-project.rs:39:24
+   |
+LL |     projection_bound::<T>();
+   |                        ^ type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
+   |
+note: types differ
+  --> $DIR/candidate-from-env-universe-err-project.rs:14:18
+   |
+LL |     type Assoc = usize;
+   |                  ^^^^^
+note: required by a bound in `projection_bound`
+  --> $DIR/candidate-from-env-universe-err-project.rs:18:42
+   |
+LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
+   |                                          ^^^^^^^^^^^^^ required by this bound in `projection_bound`
+
+error: higher-ranked subtype error
+  --> $DIR/candidate-from-env-universe-err-project.rs:55:30
+   |
+LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/candidate-from-env-universe-err-project.rs:55:30
+   |
+LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
new file mode 100644
index 00000000000..2f53bd019b7
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
@@ -0,0 +1,62 @@
+//@ revisions: next current
+//@[next] compile-flags: -Znext-solver
+
+// cc #119820 the previous behavior here was inconsistent as we discarded
+// the where-bound candidate for trait goals due to the leak check, but did
+// not do so for projection candidates and during normalization.
+//
+// This results in an inconsistency between `Trait` and `Projection` goals as
+// normalizing always constraints the normalized-to term.
+trait Trait<'a> {
+    type Assoc;
+}
+impl<'a, T> Trait<'a> for T {
+    type Assoc = usize;
+}
+
+fn trait_bound<T: for<'a> Trait<'a>>() {}
+fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
+
+// We use a function with a trivial where-bound which is more
+// restrictive than the impl.
+fn function1<T: Trait<'static>>() {
+    // err
+    //
+    // Proving `for<'a> T: Trait<'a>` using the where-bound does not
+    // result in a leak check failure even though it does not apply.
+    // We prefer env candidates over impl candidatescausing this to succeed.
+    trait_bound::<T>();
+    //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
+    //[current]~^^ ERROR implementation of `Trait` is not general enough
+}
+
+fn function2<T: Trait<'static, Assoc = usize>>() {
+    // err
+    //
+    // Proving the `Projection` goal `for<'a> T: Trait<'a, Assoc = usize>`
+    // does not use the leak check when trying the where-bound, causing us
+    // to prefer it over the impl, resulting in a placeholder error.
+    projection_bound::<T>();
+    //[next]~^ ERROR type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
+    //[next]~| ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
+    //[current]~^^^ ERROR implementation of `Trait` is not general enough
+    //[current]~| ERROR mismatched types
+}
+
+fn function3<T: Trait<'static, Assoc = usize>>() {
+    // err
+    //
+    // Trying to normalize the type `for<'a> fn(<T as Trait<'a>>::Assoc)`
+    // only gets to `<T as Trait<'a>>::Assoc` once `'a` has been already
+    // instantiated, causing us to prefer the where-bound over the impl
+    // resulting in a placeholder error. Even if were were to also use the
+    // leak check during candidate selection for normalization, this
+    // case would still not compile.
+    let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
+    //[next]~^ ERROR higher-ranked subtype error
+    //[next]~| ERROR higher-ranked subtype error
+    //[current]~^^^ ERROR mismatched types
+    //[current]~| ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/leak-check-in-selection.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-1.rs
index 46a0dccb441..46a0dccb441 100644
--- a/tests/ui/higher-ranked/leak-check-in-selection.rs
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-1.rs
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr
new file mode 100644
index 00000000000..a840304e49c
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr
@@ -0,0 +1,23 @@
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-2.rs:16:5
+   |
+LL |     impls_trait::<(), _>();
+   |     ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
+   |
+note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found
+  --> $DIR/leak-check-in-selection-2.rs:9:1
+   |
+LL | impl<'a> Trait<&'a str, &'a str> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | impl<'a> Trait<&'a str, String> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `impls_trait`
+  --> $DIR/leak-check-in-selection-2.rs:13:19
+   |
+LL | fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr
new file mode 100644
index 00000000000..a840304e49c
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr
@@ -0,0 +1,23 @@
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-2.rs:16:5
+   |
+LL |     impls_trait::<(), _>();
+   |     ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
+   |
+note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found
+  --> $DIR/leak-check-in-selection-2.rs:9:1
+   |
+LL | impl<'a> Trait<&'a str, &'a str> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | impl<'a> Trait<&'a str, String> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `impls_trait`
+  --> $DIR/leak-check-in-selection-2.rs:13:19
+   |
+LL | fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs
new file mode 100644
index 00000000000..48dd569f201
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs
@@ -0,0 +1,18 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+
+// cc #119820
+
+trait Trait<T, U> {}
+
+// using this impl results in a higher-ranked region error.
+impl<'a> Trait<&'a str, &'a str> for () {}
+
+impl<'a> Trait<&'a str, String> for () {}
+
+fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
+
+fn main() {
+    impls_trait::<(), _>();
+    //~^ ERROR type annotations needed
+}
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr
new file mode 100644
index 00000000000..8a8118dea85
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr
@@ -0,0 +1,35 @@
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-3.rs:18:5
+   |
+LL |     impls_leak::<Box<_>>();
+   |     ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak`
+   |
+note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
+  --> $DIR/leak-check-in-selection-3.rs:9:1
+   |
+LL | impl Leak<'_> for Box<u32> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Leak<'static> for Box<u16> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `impls_leak`
+  --> $DIR/leak-check-in-selection-3.rs:12:18
+   |
+LL | fn impls_leak<T: for<'a> Leak<'a>>() {}
+   |                  ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak`
+
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-3.rs:35:5
+   |
+LL |     impls_indirect_leak::<Box<_>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak`
+   |
+   = note: cannot satisfy `for<'a> Box<_>: IndirectLeak<'a>`
+note: required by a bound in `impls_indirect_leak`
+  --> $DIR/leak-check-in-selection-3.rs:25:27
+   |
+LL | fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr
new file mode 100644
index 00000000000..662a0653740
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr
@@ -0,0 +1,48 @@
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-3.rs:18:5
+   |
+LL |     impls_leak::<Box<_>>();
+   |     ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak`
+   |
+note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
+  --> $DIR/leak-check-in-selection-3.rs:9:1
+   |
+LL | impl Leak<'_> for Box<u32> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Leak<'static> for Box<u16> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `impls_leak`
+  --> $DIR/leak-check-in-selection-3.rs:12:18
+   |
+LL | fn impls_leak<T: for<'a> Leak<'a>>() {}
+   |                  ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak`
+
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-3.rs:35:5
+   |
+LL |     impls_indirect_leak::<Box<_>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak`
+   |
+note: multiple `impl`s satisfying `Box<_>: Leak<'_>` found
+  --> $DIR/leak-check-in-selection-3.rs:9:1
+   |
+LL | impl Leak<'_> for Box<u32> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Leak<'static> for Box<u16> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required for `Box<_>` to implement `for<'a> IndirectLeak<'a>`
+  --> $DIR/leak-check-in-selection-3.rs:23:23
+   |
+LL | impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {}
+   |             --------  ^^^^^^^^^^^^^^^^     ^
+   |             |
+   |             unsatisfied trait bound introduced here
+note: required by a bound in `impls_indirect_leak`
+  --> $DIR/leak-check-in-selection-3.rs:25:27
+   |
+LL | fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs
new file mode 100644
index 00000000000..9e99b6c527d
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs
@@ -0,0 +1,39 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+
+// cc #119820, the previous behavior here was inconsistent,
+// using the leak check to guide inference for `for<'a> Box<_>: Leak<'a>`
+// but not for `for<'a> Box<_>: IndirectLeak<'a>`
+
+trait Leak<'a> {}
+impl Leak<'_> for Box<u32> {}
+impl Leak<'static> for Box<u16> {}
+
+fn impls_leak<T: for<'a> Leak<'a>>() {}
+fn direct() {
+    // ok
+    //
+    // The `Box<u16>` impls fails the leak check,
+    // meaning that we apply the `Box<u32>` impl.
+    impls_leak::<Box<_>>();
+    //~^ ERROR type annotations needed
+}
+
+trait IndirectLeak<'a> {}
+impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {}
+
+fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
+fn indirect() {
+    // error: type annotations needed
+    //
+    // While the `Box<u16>` impl would fail the leak check
+    // we have already instantiated the binder while applying
+    // the generic `IndirectLeak` impl, so during candidate
+    // selection of `Leak` we do not detect the placeholder error.
+    // Evaluation of `Box<_>: Leak<'!a>` is therefore ambiguous,
+    // resulting in `for<'a> Box<_>: Leak<'a>` also being ambiguous.
+    impls_indirect_leak::<Box<_>>();
+    //~^ ERROR type annotations needed
+}
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs
new file mode 100644
index 00000000000..8d87bdd064a
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs
@@ -0,0 +1,29 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// cc #119820. While the leak check does not consider the binder
+// of the current goal, leaks from higher-ranked nested goals are
+// considered.
+//
+// We enter and exit the binder of the nested goal while evaluating
+// the candidate.
+
+trait LeakCheckFailure<'a> {}
+impl LeakCheckFailure<'static> for () {}
+
+trait Trait<T> {}
+impl Trait<u32> for () where for<'a> (): LeakCheckFailure<'a> {}
+impl Trait<u16> for () {}
+fn impls_trait<T: Trait<U>, U>() {}
+fn main() {
+    // ok
+    //
+    // It does not matter whether candidate assembly
+    // considers the placeholders from higher-ranked goal.
+    //
+    // Either `for<'a> (): LeakCheckFailure<'a>` has no applicable
+    // candidate or it has a single applicable candidate which then later
+    // results in an error. This allows us to infer `U` to `u16`.
+    impls_trait::<(), _>()
+}
diff --git a/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr b/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr
deleted file mode 100644
index b322ea41c43..00000000000
--- a/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0277]: expected a `Fn(&'w ())` closure, found `fn(&'w ())`
-  --> $DIR/fn-ptr.rs:12:5
-   |
-LL |     ice();
-   |     ^^^^^ expected an `Fn(&'w ())` closure, found `fn(&'w ())`
-   |
-   = help: the trait `for<'w> Fn<(&'w (),)>` is not implemented for `fn(&'w ())`
-note: required by a bound in `ice`
-  --> $DIR/fn-ptr.rs:7:25
-   |
-LL | fn ice()
-   |    --- required by a bound in this function
-LL | where
-LL |     for<'w> fn(&'w ()): Fn(&'w ()),
-   |                         ^^^^^^^^^^ required by this bound in `ice`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-ranked/trait-bounds/fn-ptr.current.stderr b/tests/ui/higher-ranked/trait-bounds/fn-ptr.current.stderr
deleted file mode 100644
index f3583cd218b..00000000000
--- a/tests/ui/higher-ranked/trait-bounds/fn-ptr.current.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0277]: expected a `Fn(&'w ())` closure, found `fn(&'w ())`
-  --> $DIR/fn-ptr.rs:13:5
-   |
-LL |     ice();
-   |     ^^^^^ expected an `Fn(&'w ())` closure, found `fn(&'w ())`
-   |
-   = help: the trait `for<'w> Fn<(&'w (),)>` is not implemented for `fn(&'w ())`
-note: required by a bound in `ice`
-  --> $DIR/fn-ptr.rs:8:25
-   |
-LL | fn ice()
-   |    --- required by a bound in this function
-LL | where
-LL |     for<'w> fn(&'w ()): Fn(&'w ()),
-   |                         ^^^^^^^^^^ required by this bound in `ice`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs b/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs
index 9298c10c341..7a4c15f4d4b 100644
--- a/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs
+++ b/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs
@@ -1,7 +1,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
-//@[next] check-pass
+//@ check-pass
 
 fn ice()
 where
@@ -11,5 +11,4 @@ where
 
 fn main() {
     ice();
-    //[current]~^ ERROR expected a `Fn(&'w ())` closure, found `fn(&'w ())`
 }
diff --git a/tests/ui/higher-ranked/trait-bounds/future.classic.stderr b/tests/ui/higher-ranked/trait-bounds/future.classic.stderr
deleted file mode 100644
index ef31b7266c7..00000000000
--- a/tests/ui/higher-ranked/trait-bounds/future.classic.stderr
+++ /dev/null
@@ -1,6 +0,0 @@
-error: the compiler unexpectedly panicked. this is a bug.
-
-query stack during panic:
-#0 [evaluate_obligation] evaluating trait selection obligation `for<'a> {async fn body@$DIR/future.rs:32:35: 34:2}: core::future::future::Future`
-#1 [codegen_select_candidate] computing candidate for `<strlen as Trait>`
-end of query stack
diff --git a/tests/ui/higher-ranked/trait-bounds/future.current.stderr b/tests/ui/higher-ranked/trait-bounds/future.current.stderr
deleted file mode 100644
index 673bc48a424..00000000000
--- a/tests/ui/higher-ranked/trait-bounds/future.current.stderr
+++ /dev/null
@@ -1,6 +0,0 @@
-error: the compiler unexpectedly panicked. this is a bug.
-
-query stack during panic:
-#0 [evaluate_obligation] evaluating trait selection obligation `for<'a> {async fn body of strlen()}: core::future::future::Future`
-#1 [codegen_select_candidate] computing candidate for `<strlen as Trait>`
-end of query stack
diff --git a/tests/ui/higher-ranked/trait-bounds/future.rs b/tests/ui/higher-ranked/trait-bounds/future.rs
index 4b52f04dbe0..7105015b690 100644
--- a/tests/ui/higher-ranked/trait-bounds/future.rs
+++ b/tests/ui/higher-ranked/trait-bounds/future.rs
@@ -3,14 +3,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
-//@[next] check-pass
-//@[current] known-bug: #112347
-//@[current] build-fail
-//@[current] failure-status: 101
-//@[current] normalize-stderr-test "note: .*\n\n" -> ""
-//@[current] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
-//@[current] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
-//@[current] rustc-env:RUST_BACKTRACE=0
+//@ check-pass
 
 #![feature(unboxed_closures)]
 
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.rs
index ffb2b306ae7..799df8cae9f 100644
--- a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.rs
@@ -1,6 +1,6 @@
 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
 
-// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T`
+// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T>`
 // should act as assertion that item does not borrow from its stream;
 // but an earlier buggy rustc allowed `.map(|x: &_| x)` which does
 // have such an item.
@@ -97,10 +97,6 @@ where
 
 impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
 
-fn identity<T>(x: &T) -> &T {
-    x
-}
-
 fn variant1() {
     let source = Repeat(10);
 
@@ -118,19 +114,7 @@ fn variant1() {
     // guess.
     let map = source.mapx(|x: &_| x);
     let filter = map.filterx(|x: &_| true);
-    //~^ ERROR the method
-}
-
-fn variant2() {
-    let source = Repeat(10);
-
-    // Here, we use a function, which is not subject to the vagaries
-    // of closure signature inference. In this case, we get the error
-    // on `countx` as, I think, the test originally expected.
-    let map = source.mapx(identity);
-    let filter = map.filterx(|x: &_| true);
-    let count = filter.countx();
-    //~^ ERROR the method
+    //~^ ERROR the method `filterx` exists for struct
 }
 
 fn main() {}
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr
new file mode 100644
index 00000000000..ae364de8cc0
--- /dev/null
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr
@@ -0,0 +1,27 @@
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, {closure@hrtb-doesnt-borrow-self-1.rs:115:27}>`, but its trait bounds were not satisfied
+  --> $DIR/hrtb-doesnt-borrow-self-1.rs:116:22
+   |
+LL | pub struct Map<S, F> {
+   | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt`
+...
+LL |     let filter = map.filterx(|x: &_| true);
+   |                      ^^^^^^^ method cannot be called due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `&'a mut &Map<Repeat, {closure@$DIR/hrtb-doesnt-borrow-self-1.rs:115:27: 115:34}>: Stream`
+      `&'a mut &mut Map<Repeat, {closure@$DIR/hrtb-doesnt-borrow-self-1.rs:115:27: 115:34}>: Stream`
+      `&'a mut Map<Repeat, {closure@$DIR/hrtb-doesnt-borrow-self-1.rs:115:27: 115:34}>: Stream`
+  --> $DIR/hrtb-doesnt-borrow-self-1.rs:98:50
+   |
+LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
+   |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `StreamExt` defines an item `filterx`, perhaps you need to implement it
+  --> $DIR/hrtb-doesnt-borrow-self-1.rs:66:1
+   |
+LL | pub trait StreamExt
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs
new file mode 100644
index 00000000000..92e2e7f796e
--- /dev/null
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs
@@ -0,0 +1,116 @@
+//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
+
+// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T`
+// should act as assertion that item does not borrow from its stream;
+// but an earlier buggy rustc allowed `.map(|x: &_| x)` which does
+// have such an item.
+//
+// This tests double-checks that we do not allow such behavior to leak
+// through again.
+
+pub trait Stream {
+    type Item;
+    fn next(self) -> Option<Self::Item>;
+}
+
+// Example stream
+pub struct Repeat(u64);
+
+impl<'a> Stream for &'a mut Repeat {
+    type Item = &'a u64;
+    fn next(self) -> Option<Self::Item> {
+        Some(&self.0)
+    }
+}
+
+pub struct Map<S, F> {
+    stream: S,
+    func: F,
+}
+
+impl<'a, A, F, T> Stream for &'a mut Map<A, F>
+where
+    &'a mut A: Stream,
+    F: FnMut(<&'a mut A as Stream>::Item) -> T,
+{
+    type Item = T;
+    fn next(self) -> Option<T> {
+        match self.stream.next() {
+            Some(item) => Some((self.func)(item)),
+            None => None,
+        }
+    }
+}
+
+pub struct Filter<S, F> {
+    stream: S,
+    func: F,
+}
+
+impl<'a, A, F, T> Stream for &'a mut Filter<A, F>
+where
+    for<'b> &'b mut A: Stream<Item = T>, // <---- BAD
+    F: FnMut(&T) -> bool,
+{
+    type Item = <&'a mut A as Stream>::Item;
+    fn next(self) -> Option<Self::Item> {
+        while let Some(item) = self.stream.next() {
+            if (self.func)(&item) {
+                return Some(item);
+            }
+        }
+        None
+    }
+}
+
+pub trait StreamExt
+where
+    for<'b> &'b mut Self: Stream,
+{
+    fn mapx<F>(self, func: F) -> Map<Self, F>
+    where
+        Self: Sized,
+        for<'a> &'a mut Map<Self, F>: Stream,
+    {
+        Map { func: func, stream: self }
+    }
+
+    fn filterx<F>(self, func: F) -> Filter<Self, F>
+    where
+        Self: Sized,
+        for<'a> &'a mut Filter<Self, F>: Stream,
+    {
+        Filter { func: func, stream: self }
+    }
+
+    fn countx(mut self) -> usize
+    where
+        Self: Sized,
+    {
+        let mut count = 0;
+        while let Some(_) = self.next() {
+            count += 1;
+        }
+        count
+    }
+}
+
+impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
+
+fn identity<T>(x: &T) -> &T {
+    x
+}
+
+fn variant2() {
+    let source = Repeat(10);
+
+    // Here, we use a function, which is not subject to the vagaries
+    // of closure signature inference. In this case, we get the error
+    // on `countx` as, I think, the test originally expected.
+    let map = source.mapx(identity);
+    let filter = map.filterx(|x: &_| true);
+    let count = filter.countx();
+    //~^ ERROR the method
+}
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr
new file mode 100644
index 00000000000..eeb4e12fa8b
--- /dev/null
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr
@@ -0,0 +1,27 @@
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, fn(&u64) -> &u64 {identity::<u64>}>, {closure@hrtb-doesnt-borrow-self-2.rs:111:30}>`, but its trait bounds were not satisfied
+  --> $DIR/hrtb-doesnt-borrow-self-2.rs:112:24
+   |
+LL | pub struct Filter<S, F> {
+   | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt`
+...
+LL |     let count = filter.countx();
+   |                        ^^^^^^ method cannot be called due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream`
+      `&'a mut &mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream`
+      `&'a mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream`
+  --> $DIR/hrtb-doesnt-borrow-self-2.rs:98:50
+   |
+LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
+   |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `StreamExt` defines an item `countx`, perhaps you need to implement it
+  --> $DIR/hrtb-doesnt-borrow-self-2.rs:66:1
+   |
+LL | pub trait StreamExt
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr
index e10da26665e..be19bf85bd2 100644
--- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr
@@ -1,23 +1,11 @@
-error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
-  --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26
+error: implementation of `Bar` is not general enough
+  --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5
    |
 LL |     want_bar_for_any_ccx(b);
-   |     -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
-   |     |
-   |     required by a bound introduced by this call
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
    |
-note: required by a bound in `want_bar_for_any_ccx`
-  --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:32:15
-   |
-LL | fn want_bar_for_any_ccx<B>(b: &B)
-   |    -------------------- required by a bound in this function
-LL |     where B : for<'ccx> Bar<'ccx>
-   |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
-help: consider further restricting this bound
-   |
-LL |     where B : Qux + for<'ccx> Bar<'ccx>
-   |                   +++++++++++++++++++++
+   = note: `B` must implement `Bar<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Bar<'static>`
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs
index 33e0ec4635b..70ce580258d 100644
--- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs
@@ -1,43 +1,37 @@
 // Test a trait (`Bar`) with a higher-ranked supertrait.
+#![allow(unconditional_recursion)]
 
-trait Foo<'tcx>
-{
+trait Foo<'tcx> {
     fn foo(&'tcx self) -> &'tcx isize;
 }
 
-trait Bar<'ccx>
-    : for<'tcx> Foo<'tcx>
-{
+trait Bar<'ccx>: for<'tcx> Foo<'tcx> {
     fn bar(&'ccx self) -> &'ccx isize;
 }
 
-fn want_foo_for_some_tcx<'x,F>(f: &'x F)
-    where F : Foo<'x>
-{
+fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) {
     want_foo_for_some_tcx(f);
-    want_foo_for_any_tcx(f); //~ ERROR not satisfied
+    want_foo_for_any_tcx(f);
+    //~^ ERROR lifetime may not live long enough
+    //~| ERROR implementation of `Foo` is not general enough
 }
 
-fn want_foo_for_any_tcx<F>(f: &F) //~ WARN cannot return without recursing
-    where F : for<'tcx> Foo<'tcx>
-{
+fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
     want_foo_for_some_tcx(f);
     want_foo_for_any_tcx(f);
 }
 
-fn want_bar_for_some_ccx<'x,B>(b: &B)
-    where B : Bar<'x>
-{
+fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
     want_foo_for_some_tcx(b);
     want_foo_for_any_tcx(b);
 
     want_bar_for_some_ccx(b);
-    want_bar_for_any_ccx(b); //~ ERROR not satisfied
+    want_bar_for_any_ccx(b);
+    //~^ ERROR lifetime may not live long enough
+    //~| ERROR implementation of `Bar` is not general enough
 }
 
-fn want_bar_for_any_ccx<B>(b: &B) //~ WARN cannot return without recursing
-    where B : for<'ccx> Bar<'ccx>
-{
+fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
     want_foo_for_some_tcx(b);
     want_foo_for_any_tcx(b);
 
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr
index f220ba6f338..dd760926ea1 100644
--- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr
@@ -1,68 +1,50 @@
-error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:18:26
+error: lifetime may not live long enough
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:14:5
    |
+LL | fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) {
+   |                          -- lifetime `'x` defined here
+LL |     want_foo_for_some_tcx(f);
 LL |     want_foo_for_any_tcx(f);
-   |     -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
-   |     |
-   |     required by a bound introduced by this call
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
    |
-note: required by a bound in `want_foo_for_any_tcx`
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:22:15
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:19:28
    |
-LL | fn want_foo_for_any_tcx<F>(f: &F)
-   |    -------------------- required by a bound in this function
-LL |     where F : for<'tcx> Foo<'tcx>
-   |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_foo_for_any_tcx`
-help: consider further restricting this bound
-   |
-LL |     where F : Foo<'x> + for<'tcx> Foo<'tcx>
-   |                       +++++++++++++++++++++
+LL | fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
+   |                            ^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:35:26
-   |
-LL |     want_bar_for_any_ccx(b);
-   |     -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
-   |     |
-   |     required by a bound introduced by this call
+error: implementation of `Foo` is not general enough
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:14:5
    |
-note: required by a bound in `want_bar_for_any_ccx`
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:39:15
-   |
-LL | fn want_bar_for_any_ccx<B>(b: &B)
-   |    -------------------- required by a bound in this function
-LL |     where B : for<'ccx> Bar<'ccx>
-   |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
-help: consider further restricting this bound
+LL |     want_foo_for_any_tcx(f);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-LL |     where B : Bar<'x> + for<'ccx> Bar<'ccx>
-   |                       +++++++++++++++++++++
+   = note: `F` must implement `Foo<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Foo<'1>`, for some specific lifetime `'1`
 
-warning: function cannot return without recursing
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:21:1
+error: lifetime may not live long enough
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
    |
-LL | / fn want_foo_for_any_tcx<F>(f: &F)
-LL | |     where F : for<'tcx> Foo<'tcx>
-   | |_________________________________^ cannot return without recursing
+LL | fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
+   |                          -- lifetime `'x` defined here
 ...
-LL |       want_foo_for_any_tcx(f);
-   |       ----------------------- recursive call site
+LL |     want_bar_for_any_ccx(b);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:34:28
    |
-   = help: a `loop` may express intention better if this is on purpose
-   = note: `#[warn(unconditional_recursion)]` on by default
+LL | fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
+   |                            ^^^^^^^^^^^^^^^^^^^
 
-warning: function cannot return without recursing
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:38:1
+error: implementation of `Bar` is not general enough
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
    |
-LL | / fn want_bar_for_any_ccx<B>(b: &B)
-LL | |     where B : for<'ccx> Bar<'ccx>
-   | |_________________________________^ cannot return without recursing
-...
-LL |       want_bar_for_any_ccx(b);
-   |       ----------------------- recursive call site
+LL |     want_bar_for_any_ccx(b);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
    |
-   = help: a `loop` may express intention better if this is on purpose
+   = note: `B` must implement `Bar<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Bar<'1>`, for some specific lifetime `'1`
 
-error: aborting due to 2 previous errors; 2 warnings emitted
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr
deleted file mode 100644
index 699a4ecc42b..00000000000
--- a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr
+++ /dev/null
@@ -1,51 +0,0 @@
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, {closure@issue-30786.rs:119:27}>`, but its trait bounds were not satisfied
-  --> $DIR/issue-30786.rs:120:22
-   |
-LL | pub struct Map<S, F> {
-   | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt`
-...
-LL |     let filter = map.filterx(|x: &_| true);
-   |                      ^^^^^^^ method cannot be called on `Map<Repeat, {closure@issue-30786.rs:119:27}>` due to unsatisfied trait bounds
-   |
-note: the following trait bounds were not satisfied:
-      `&'a mut &Map<Repeat, {closure@$DIR/issue-30786.rs:119:27: 119:34}>: Stream`
-      `&'a mut &mut Map<Repeat, {closure@$DIR/issue-30786.rs:119:27: 119:34}>: Stream`
-      `&'a mut Map<Repeat, {closure@$DIR/issue-30786.rs:119:27: 119:34}>: Stream`
-  --> $DIR/issue-30786.rs:98:50
-   |
-LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
-   |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
-   = help: items from traits can only be used if the trait is implemented and in scope
-note: `StreamExt` defines an item `filterx`, perhaps you need to implement it
-  --> $DIR/issue-30786.rs:66:1
-   |
-LL | pub trait StreamExt
-   | ^^^^^^^^^^^^^^^^^^^
-
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, fn(&u64) -> &u64 {identity::<u64>}>, {closure@issue-30786.rs:131:30}>`, but its trait bounds were not satisfied
-  --> $DIR/issue-30786.rs:132:24
-   |
-LL | pub struct Filter<S, F> {
-   | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt`
-...
-LL |     let count = filter.countx();
-   |                        ^^^^^^ method cannot be called due to unsatisfied trait bounds
-   |
-note: the following trait bounds were not satisfied:
-      `&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream`
-      `&'a mut &mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream`
-      `&'a mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream`
-  --> $DIR/issue-30786.rs:98:50
-   |
-LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
-   |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
-   = help: items from traits can only be used if the trait is implemented and in scope
-note: `StreamExt` defines an item `countx`, perhaps you need to implement it
-  --> $DIR/issue-30786.rs:66:1
-   |
-LL | pub trait StreamExt
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs
index ab21dae7dc5..7a51037324f 100644
--- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs
+++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs
@@ -14,6 +14,7 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I {
     //~^ ERROR binding for associated type `Item` references lifetime `'missing`
     //~| ERROR binding for associated type `Item` references lifetime `'missing`
     //~| ERROR `()` is not an iterator
+    //~| WARNING impl trait in impl method signature does not match trait method signature
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr
index d8a2eef94a1..67c4df0f3a9 100644
--- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr
+++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr
@@ -32,7 +32,24 @@ LL |     fn iter(&self) -> impl for<'missing> Iterator<Item = Self::Item<'missin
    |
    = help: the trait `Iterator` is not implemented for `()`
 
-error: aborting due to 4 previous errors
+warning: impl trait in impl method signature does not match trait method signature
+  --> $DIR/span-bug-issue-121457.rs:13:51
+   |
+LL |     fn iter(&self) -> impl Iterator;
+   |                       ------------- return type from trait method defined here
+...
+LL |     fn iter(&self) -> impl for<'missing> Iterator<Item = Self::Item<'missing>> {}
+   |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this bound is stronger than that defined on the trait
+   |
+   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+   = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
+   = note: `#[warn(refining_impl_trait_reachable)]` on by default
+help: replace the return type so that it matches the trait
+   |
+LL |     fn iter(&self) -> impl Iterator {}
+   |                       ~~~~~~~~~~~~~
+
+error: aborting due to 4 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0195, E0277, E0582.
 For more information about an error, try `rustc --explain E0195`.
diff --git a/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs
new file mode 100644
index 00000000000..0e07d21b2f5
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs
@@ -0,0 +1,11 @@
+// Don't panic when iterating through the `hir::Map::parent_iter` of an RPITIT.
+
+pub trait Foo {
+    fn demo() -> impl Foo
+    //~^ ERROR the trait bound `String: Copy` is not satisfied
+    where
+        String: Copy;
+    //~^ ERROR the trait bound `String: Copy` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr
new file mode 100644
index 00000000000..8ff8f12cdf4
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/synthetic-hir-has-parent.rs:7:9
+   |
+LL |         String: Copy;
+   |         ^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+   = help: see issue #48214
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+LL + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/synthetic-hir-has-parent.rs:4:18
+   |
+LL |     fn demo() -> impl Foo
+   |                  ^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+   = help: see issue #48214
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+LL + #![feature(trivial_bounds)]
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/implied-bounds/issue-100690.rs b/tests/ui/implied-bounds/issue-100690.rs
index ea33c9f423b..041c687ec94 100644
--- a/tests/ui/implied-bounds/issue-100690.rs
+++ b/tests/ui/implied-bounds/issue-100690.rs
@@ -4,11 +4,8 @@
 use std::io;
 
 fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
-//~^ NOTE required by a bound in this
 where
     F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
-    //~^ NOTE required by this bound in `real_dispatch`
-    //~| NOTE required by a bound in `real_dispatch`
 {
     todo!()
 }
@@ -35,10 +32,10 @@ impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandl
         F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static,
     {
         real_dispatch(f)
-        //~^ ERROR expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F`
-        //~| NOTE expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F`
-        //~| NOTE expected a closure with arguments
-        //~| NOTE required by a bound introduced by this call
+        //~^ ERROR lifetime may not live long enough
+        //~| ERROR implementation of `FnOnce` is not general enough
+        //~| ERROR mismatched types
+        //
     }
 }
 
diff --git a/tests/ui/implied-bounds/issue-100690.stderr b/tests/ui/implied-bounds/issue-100690.stderr
index df069d875ce..2cfd028f255 100644
--- a/tests/ui/implied-bounds/issue-100690.stderr
+++ b/tests/ui/implied-bounds/issue-100690.stderr
@@ -1,22 +1,41 @@
-error[E0277]: expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F`
-  --> $DIR/issue-100690.rs:37:23
+error: lifetime may not live long enough
+  --> $DIR/issue-100690.rs:34:9
    |
+LL | impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandle<T> {
+   |      -- lifetime `'a` defined here
+...
 LL |         real_dispatch(f)
-   |         ------------- ^ expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F`
-   |         |
-   |         required by a bound introduced by this call
+   |         ^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
    |
-   = note: expected a closure with arguments `(&mut UIView<'a, _>,)`
-              found a closure with arguments `(&mut UIView<'_, _>,)`
-note: required by a bound in `real_dispatch`
-  --> $DIR/issue-100690.rs:9:8
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/issue-100690.rs:8:8
+   |
+LL |     F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/issue-100690.rs:34:9
+   |
+LL |         real_dispatch(f)
+   |         ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: `F` must implement `FnOnce<(&mut UIView<'0, T>,)>`, for any lifetime `'0`...
+   = note: ...but it actually implements `FnOnce<(&mut UIView<'1, T>,)>`, for some specific lifetime `'1`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-100690.rs:34:9
+   |
+LL |         real_dispatch(f)
+   |         ^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected associated type `<F as FnOnce<(&mut UIView<'_, T>,)>>::Output`
+              found associated type `<F as FnOnce<(&mut UIView<'_, T>,)>>::Output`
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-100690.rs:8:34
    |
-LL | fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
-   |    ------------- required by a bound in this function
-...
 LL |     F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `real_dispatch`
+   |                                  ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 1 previous error
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/issues/issue-1476.rs b/tests/ui/issues/issue-1476.rs
deleted file mode 100644
index 138570a93c4..00000000000
--- a/tests/ui/issues/issue-1476.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    println!("{}", x); //~ ERROR cannot find value `x` in this scope
-}
diff --git a/tests/ui/issues/issue-1476.stderr b/tests/ui/issues/issue-1476.stderr
deleted file mode 100644
index e30dbfd205b..00000000000
--- a/tests/ui/issues/issue-1476.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0425]: cannot find value `x` in this scope
-  --> $DIR/issue-1476.rs:2:20
-   |
-LL |     println!("{}", x);
-   |                    ^ not found in this scope
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/issues/issue-1696.rs b/tests/ui/issues/issue-1696.rs
deleted file mode 100644
index 08002ad3c58..00000000000
--- a/tests/ui/issues/issue-1696.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ run-pass
-use std::collections::HashMap;
-
-pub fn main() {
-    let mut m = HashMap::new();
-    m.insert(b"foo".to_vec(), b"bar".to_vec());
-    println!("{:?}", m);
-}
diff --git a/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs
new file mode 100644
index 00000000000..737a7ffbc29
--- /dev/null
+++ b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs
@@ -0,0 +1,79 @@
+// Regression test for #121473
+// Checks that no ICE occurs when `size_of`
+// is applied to a struct that has an unsized
+// field which is not its last field
+
+use std::mem::size_of;
+
+pub struct BadStruct {
+    pub field1: i32,
+    pub field2: str, // Unsized field that is not the last field
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    pub field3: [u8; 16],
+}
+
+enum BadEnum1 {
+    Variant1 {
+        field1: i32,
+        field2: str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        field3: [u8; 16],
+    },
+}
+
+enum BadEnum2 {
+    Variant1(
+        i32,
+        str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        [u8; 16]
+    ),
+}
+
+enum BadEnumMultiVariant {
+    Variant1(i32),
+    Variant2 {
+        field1: i32,
+        field2: str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        field3: [u8; 16],
+    },
+    Variant3
+}
+
+union BadUnion {
+    field1: i32,
+    field2: str, // Unsized
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    //~| ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+    field3: [u8; 16],
+}
+
+// Used to test that projection type fields that normalize
+// to a sized type do not cause problems
+struct StructWithProjections<'a>
+{
+    field1: <&'a [i32] as IntoIterator>::IntoIter,
+    field2: i32
+}
+
+pub fn main() {
+    let _a = &size_of::<BadStruct>();
+    assert_eq!(size_of::<BadStruct>(), 21);
+
+    let _a = &size_of::<BadEnum1>();
+    assert_eq!(size_of::<BadEnum1>(), 21);
+
+    let _a = &size_of::<BadEnum2>();
+    assert_eq!(size_of::<BadEnum2>(), 21);
+
+    let _a = &size_of::<BadEnumMultiVariant>();
+    assert_eq!(size_of::<BadEnumMultiVariant>(), 21);
+
+    let _a = &size_of::<BadUnion>();
+    assert_eq!(size_of::<BadUnion>(), 21);
+
+    let _a = &size_of::<StructWithProjections>();
+    assert_eq!(size_of::<StructWithProjections>(), 21);
+    let _a = StructWithProjections { field1: [1, 3].iter(), field2: 3 };
+}
diff --git a/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr
new file mode 100644
index 00000000000..626be7ac283
--- /dev/null
+++ b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr
@@ -0,0 +1,106 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:10:17
+   |
+LL |     pub field2: str, // Unsized field that is not the last field
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     pub field2: &str, // Unsized field that is not the last field
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     pub field2: Box<str>, // Unsized field that is not the last field
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:18:17
+   |
+LL |         field2: str, // Unsized
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         field2: &str, // Unsized
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         field2: Box<str>, // Unsized
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:27:9
+   |
+LL |         str, // Unsized
+   |         ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         &str, // Unsized
+   |         +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         Box<str>, // Unsized
+   |         ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:37:17
+   |
+LL |         field2: str, // Unsized
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         field2: &str, // Unsized
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         field2: Box<str>, // Unsized
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:13
+   |
+LL |     field2: str, // Unsized
+   |             ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     field2: &str, // Unsized
+   |             +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     field2: Box<str>, // Unsized
+   |             ++++   +
+
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:5
+   |
+LL |     field2: str, // Unsized
+   |     ^^^^^^^^^^^
+   |
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
+   |
+LL |     field2: std::mem::ManuallyDrop<str>, // Unsized
+   |             +++++++++++++++++++++++   +
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0277, E0740.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/lifetimes/issue-105675.rs b/tests/ui/lifetimes/issue-105675.rs
index 2e2eaca0d33..0472537e7f3 100644
--- a/tests/ui/lifetimes/issue-105675.rs
+++ b/tests/ui/lifetimes/issue-105675.rs
@@ -4,7 +4,7 @@ fn main() {
     let f = | _ , y: &u32 , z | ();
     thing(f);
     //~^ ERROR implementation of `FnOnce` is not general enough
-    //~^^ ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
     let f = | x, y: _  , z: u32 | ();
     thing(f);
     //~^ ERROR implementation of `FnOnce` is not general enough
diff --git a/tests/ui/lifetimes/lifetime-errors/issue_74400.rs b/tests/ui/lifetimes/lifetime-errors/issue_74400.rs
index b02e38bec3b..72345fa294a 100644
--- a/tests/ui/lifetimes/lifetime-errors/issue_74400.rs
+++ b/tests/ui/lifetimes/lifetime-errors/issue_74400.rs
@@ -1,5 +1,5 @@
 //! Regression test for #74400: Type mismatch in function arguments E0631, E0271 are falsely
-//! recognized as E0308 mismatched types.
+//! recognized as "implementation of `FnOnce` is not general enough".
 
 use std::convert::identity;
 
@@ -13,6 +13,6 @@ fn g<T>(data: &[T]) {
     //~^ ERROR the parameter type
     //~| ERROR the parameter type
     //~| ERROR the parameter type
-    //~| ERROR implementation of `FnOnce` is not general
+    //~| ERROR implementation of `FnOnce` is not general enough
     //~| ERROR implementation of `Fn` is not general enough
 }
diff --git a/tests/ui/lint/lint-strict-provenance-fuzzy-casts.stderr b/tests/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
index 0b128974275..24f2500abf8 100644
--- a/tests/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
+++ b/tests/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
@@ -4,7 +4,7 @@ error: strict provenance disallows casting integer `usize` to pointer `*const u8
 LL |     let dangling = 16_usize as *const u8;
    |                    ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
+   = help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead
 note: the lint level is defined here
   --> $DIR/lint-strict-provenance-fuzzy-casts.rs:2:9
    |
diff --git a/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr b/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr
index aa151fe2d21..390028b349e 100644
--- a/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr
+++ b/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr
@@ -4,7 +4,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons
 LL |     let addr: usize = &x as *const u8 as usize;
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 note: the lint level is defined here
   --> $DIR/lint-strict-provenance-lossy-casts.rs:2:9
    |
@@ -21,7 +21,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons
 LL |     let addr_32bit = &x as *const u8 as u32;
    |                      ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 help: use `.addr()` to obtain the address of a pointer
    |
 LL |     let addr_32bit = (&x as *const u8).addr() as u32;
@@ -35,7 +35,7 @@ LL |     let ptr_addr = ptr as usize;
    |                       |
    |                       help: use `.addr()` to obtain the address of a pointer: `.addr()`
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 
 error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
   --> $DIR/lint-strict-provenance-lossy-casts.rs:16:26
@@ -45,7 +45,7 @@ LL |     let ptr_addr_32bit = ptr as u32;
    |                             |
    |                             help: use `.addr()` to obtain the address of a pointer: `.addr() as u32`
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/lint/wide_pointer_comparisons.rs b/tests/ui/lint/wide_pointer_comparisons.rs
index 31369001075..05097cbf1e3 100644
--- a/tests/ui/lint/wide_pointer_comparisons.rs
+++ b/tests/ui/lint/wide_pointer_comparisons.rs
@@ -3,6 +3,7 @@
 use std::rc::Rc;
 use std::sync::Arc;
 use std::cmp::PartialEq;
+use std::ptr::NonNull;
 
 struct A;
 struct B;
@@ -37,6 +38,29 @@ fn main() {
     //~^ WARN ambiguous wide pointer comparison
     let _ = a.ne(&b);
     //~^ WARN ambiguous wide pointer comparison
+    let _ = a.cmp(&b);
+    //~^ WARN ambiguous wide pointer comparison
+    let _ = a.partial_cmp(&b);
+    //~^ WARN ambiguous wide pointer comparison
+    let _ = a.le(&b);
+    //~^ WARN ambiguous wide pointer comparison
+    let _ = a.lt(&b);
+    //~^ WARN ambiguous wide pointer comparison
+    let _ = a.ge(&b);
+    //~^ WARN ambiguous wide pointer comparison
+    let _ = a.gt(&b);
+    //~^ WARN ambiguous wide pointer comparison
+
+    {
+        let a = NonNull::<dyn T>::new(a as *mut _).unwrap();
+        let b = NonNull::<dyn T>::new(b as *mut _).unwrap();
+        let _ = a == b;
+        //~^ WARN ambiguous wide pointer comparison
+        let _ = a >= b;
+        //~^ WARN ambiguous wide pointer comparison
+        let _ = &a == &b;
+        //~^ WARN ambiguous wide pointer comparison
+    }
 
     {
         // &*const ?Sized
@@ -68,6 +92,18 @@ fn main() {
         //~^ WARN ambiguous wide pointer comparison
         let _ = a.ne(b);
         //~^ WARN ambiguous wide pointer comparison
+        let _ = a.cmp(&b);
+        //~^ WARN ambiguous wide pointer comparison
+        let _ = a.partial_cmp(&b);
+        //~^ WARN ambiguous wide pointer comparison
+        let _ = a.le(&b);
+        //~^ WARN ambiguous wide pointer comparison
+        let _ = a.lt(&b);
+        //~^ WARN ambiguous wide pointer comparison
+        let _ = a.ge(&b);
+        //~^ WARN ambiguous wide pointer comparison
+        let _ = a.gt(&b);
+        //~^ WARN ambiguous wide pointer comparison
     }
 
     let s = "" as *const str;
diff --git a/tests/ui/lint/wide_pointer_comparisons.stderr b/tests/ui/lint/wide_pointer_comparisons.stderr
index 6ef117c63c5..81a221c0ee6 100644
--- a/tests/ui/lint/wide_pointer_comparisons.stderr
+++ b/tests/ui/lint/wide_pointer_comparisons.stderr
@@ -1,5 +1,5 @@
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:19:13
+  --> $DIR/wide_pointer_comparisons.rs:20:13
    |
 LL |     let _ = a == b;
    |             ^^^^^^
@@ -11,7 +11,7 @@ LL |     let _ = std::ptr::addr_eq(a, b);
    |             ++++++++++++++++++ ~  +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:21:13
+  --> $DIR/wide_pointer_comparisons.rs:22:13
    |
 LL |     let _ = a != b;
    |             ^^^^^^
@@ -22,51 +22,51 @@ LL |     let _ = !std::ptr::addr_eq(a, b);
    |             +++++++++++++++++++ ~  +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:23:13
+  --> $DIR/wide_pointer_comparisons.rs:24:13
    |
 LL |     let _ = a < b;
    |             ^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |     let _ = a as *const () < b as *const ();
-   |               ++++++++++++     ++++++++++++
+LL |     let _ = a.cast::<()>() < b.cast::<()>();
+   |              +++++++++++++    +++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:25:13
+  --> $DIR/wide_pointer_comparisons.rs:26:13
    |
 LL |     let _ = a <= b;
    |             ^^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |     let _ = a as *const () <= b as *const ();
-   |               ++++++++++++      ++++++++++++
+LL |     let _ = a.cast::<()>() <= b.cast::<()>();
+   |              +++++++++++++     +++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:27:13
+  --> $DIR/wide_pointer_comparisons.rs:28:13
    |
 LL |     let _ = a > b;
    |             ^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |     let _ = a as *const () > b as *const ();
-   |               ++++++++++++     ++++++++++++
+LL |     let _ = a.cast::<()>() > b.cast::<()>();
+   |              +++++++++++++    +++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:29:13
+  --> $DIR/wide_pointer_comparisons.rs:30:13
    |
 LL |     let _ = a >= b;
    |             ^^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |     let _ = a as *const () >= b as *const ();
-   |               ++++++++++++      ++++++++++++
+LL |     let _ = a.cast::<()>() >= b.cast::<()>();
+   |              +++++++++++++     +++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:32:13
+  --> $DIR/wide_pointer_comparisons.rs:33:13
    |
 LL |     let _ = PartialEq::eq(&a, &b);
    |             ^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     let _ = std::ptr::addr_eq(a, b);
    |             ~~~~~~~~~~~~~~~~~~ ~  ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:34:13
+  --> $DIR/wide_pointer_comparisons.rs:35:13
    |
 LL |     let _ = PartialEq::ne(&a, &b);
    |             ^^^^^^^^^^^^^^^^^^^^^
@@ -88,7 +88,7 @@ LL |     let _ = !std::ptr::addr_eq(a, b);
    |             ~~~~~~~~~~~~~~~~~~~ ~  ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:36:13
+  --> $DIR/wide_pointer_comparisons.rs:37:13
    |
 LL |     let _ = a.eq(&b);
    |             ^^^^^^^^
@@ -99,7 +99,7 @@ LL |     let _ = std::ptr::addr_eq(a, b);
    |             ++++++++++++++++++ ~  ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:38:13
+  --> $DIR/wide_pointer_comparisons.rs:39:13
    |
 LL |     let _ = a.ne(&b);
    |             ^^^^^^^^
@@ -110,7 +110,106 @@ LL |     let _ = !std::ptr::addr_eq(a, b);
    |             +++++++++++++++++++ ~  ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:46:17
+  --> $DIR/wide_pointer_comparisons.rs:41:13
+   |
+LL |     let _ = a.cmp(&b);
+   |             ^^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |     let _ = a.cast::<()>().cmp(&b.cast::<()>());
+   |              +++++++++++++       +++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:43:13
+   |
+LL |     let _ = a.partial_cmp(&b);
+   |             ^^^^^^^^^^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |     let _ = a.cast::<()>().partial_cmp(&b.cast::<()>());
+   |              +++++++++++++               +++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:45:13
+   |
+LL |     let _ = a.le(&b);
+   |             ^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |     let _ = a.cast::<()>().le(&b.cast::<()>());
+   |              +++++++++++++      +++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:47:13
+   |
+LL |     let _ = a.lt(&b);
+   |             ^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |     let _ = a.cast::<()>().lt(&b.cast::<()>());
+   |              +++++++++++++      +++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:49:13
+   |
+LL |     let _ = a.ge(&b);
+   |             ^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |     let _ = a.cast::<()>().ge(&b.cast::<()>());
+   |              +++++++++++++      +++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:51:13
+   |
+LL |     let _ = a.gt(&b);
+   |             ^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |     let _ = a.cast::<()>().gt(&b.cast::<()>());
+   |              +++++++++++++      +++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:57:17
+   |
+LL |         let _ = a == b;
+   |                 ^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |         let _ = std::ptr::addr_eq(a.as_ptr(), b.as_ptr());
+   |                 ++++++++++++++++++ ~~~~~~~~~~  ++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:59:17
+   |
+LL |         let _ = a >= b;
+   |                 ^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |         let _ = a.as_ptr().cast::<()>() >= b.as_ptr().cast::<()>();
+   |                  ++++++++++++++++++++++     ++++++++++++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:61:17
+   |
+LL |         let _ = &a == &b;
+   |                 ^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |         let _ = std::ptr::addr_eq(a.as_ptr(), b.as_ptr());
+   |                 ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~  ++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:70:17
    |
 LL |         let _ = a == b;
    |                 ^^^^^^
@@ -121,7 +220,7 @@ LL |         let _ = std::ptr::addr_eq(*a, *b);
    |                 +++++++++++++++++++ ~~~ +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:48:17
+  --> $DIR/wide_pointer_comparisons.rs:72:17
    |
 LL |         let _ = a != b;
    |                 ^^^^^^
@@ -132,51 +231,51 @@ LL |         let _ = !std::ptr::addr_eq(*a, *b);
    |                 ++++++++++++++++++++ ~~~ +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:50:17
+  --> $DIR/wide_pointer_comparisons.rs:74:17
    |
 LL |         let _ = a < b;
    |                 ^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |         let _ = *a as *const () < *b as *const ();
-   |                 +  ++++++++++++   +  ++++++++++++
+LL |         let _ = (*a).cast::<()>() < (*b).cast::<()>();
+   |                 ++ ++++++++++++++   ++ ++++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:52:17
+  --> $DIR/wide_pointer_comparisons.rs:76:17
    |
 LL |         let _ = a <= b;
    |                 ^^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |         let _ = *a as *const () <= *b as *const ();
-   |                 +  ++++++++++++    +  ++++++++++++
+LL |         let _ = (*a).cast::<()>() <= (*b).cast::<()>();
+   |                 ++ ++++++++++++++    ++ ++++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:54:17
+  --> $DIR/wide_pointer_comparisons.rs:78:17
    |
 LL |         let _ = a > b;
    |                 ^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |         let _ = *a as *const () > *b as *const ();
-   |                 +  ++++++++++++   +  ++++++++++++
+LL |         let _ = (*a).cast::<()>() > (*b).cast::<()>();
+   |                 ++ ++++++++++++++   ++ ++++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:56:17
+  --> $DIR/wide_pointer_comparisons.rs:80:17
    |
 LL |         let _ = a >= b;
    |                 ^^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |         let _ = *a as *const () >= *b as *const ();
-   |                 +  ++++++++++++    +  ++++++++++++
+LL |         let _ = (*a).cast::<()>() >= (*b).cast::<()>();
+   |                 ++ ++++++++++++++    ++ ++++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:59:17
+  --> $DIR/wide_pointer_comparisons.rs:83:17
    |
 LL |         let _ = PartialEq::eq(a, b);
    |                 ^^^^^^^^^^^^^^^^^^^
@@ -187,7 +286,7 @@ LL |         let _ = std::ptr::addr_eq(*a, *b);
    |                 ~~~~~~~~~~~~~~~~~~~ ~~~ ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:61:17
+  --> $DIR/wide_pointer_comparisons.rs:85:17
    |
 LL |         let _ = PartialEq::ne(a, b);
    |                 ^^^^^^^^^^^^^^^^^^^
@@ -198,7 +297,7 @@ LL |         let _ = !std::ptr::addr_eq(*a, *b);
    |                 ~~~~~~~~~~~~~~~~~~~~ ~~~ ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:63:17
+  --> $DIR/wide_pointer_comparisons.rs:87:17
    |
 LL |         let _ = PartialEq::eq(&a, &b);
    |                 ^^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +308,7 @@ LL |         let _ = std::ptr::addr_eq(*a, *b);
    |                 ~~~~~~~~~~~~~~~~~~~ ~~~ ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:65:17
+  --> $DIR/wide_pointer_comparisons.rs:89:17
    |
 LL |         let _ = PartialEq::ne(&a, &b);
    |                 ^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +319,7 @@ LL |         let _ = !std::ptr::addr_eq(*a, *b);
    |                 ~~~~~~~~~~~~~~~~~~~~ ~~~ ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:67:17
+  --> $DIR/wide_pointer_comparisons.rs:91:17
    |
 LL |         let _ = a.eq(b);
    |                 ^^^^^^^
@@ -231,7 +330,7 @@ LL |         let _ = std::ptr::addr_eq(*a, *b);
    |                 +++++++++++++++++++ ~~~ ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:69:17
+  --> $DIR/wide_pointer_comparisons.rs:93:17
    |
 LL |         let _ = a.ne(b);
    |                 ^^^^^^^
@@ -242,7 +341,73 @@ LL |         let _ = !std::ptr::addr_eq(*a, *b);
    |                 ++++++++++++++++++++ ~~~ ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:74:13
+  --> $DIR/wide_pointer_comparisons.rs:95:17
+   |
+LL |         let _ = a.cmp(&b);
+   |                 ^^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |         let _ = (*a).cast::<()>().cmp(&(*b).cast::<()>());
+   |                 ++ ++++++++++++++      ++ ++++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:97:17
+   |
+LL |         let _ = a.partial_cmp(&b);
+   |                 ^^^^^^^^^^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |         let _ = (*a).cast::<()>().partial_cmp(&(*b).cast::<()>());
+   |                 ++ ++++++++++++++              ++ ++++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:99:17
+   |
+LL |         let _ = a.le(&b);
+   |                 ^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |         let _ = (*a).cast::<()>().le(&(*b).cast::<()>());
+   |                 ++ ++++++++++++++     ++ ++++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:101:17
+   |
+LL |         let _ = a.lt(&b);
+   |                 ^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |         let _ = (*a).cast::<()>().lt(&(*b).cast::<()>());
+   |                 ++ ++++++++++++++     ++ ++++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:103:17
+   |
+LL |         let _ = a.ge(&b);
+   |                 ^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |         let _ = (*a).cast::<()>().ge(&(*b).cast::<()>());
+   |                 ++ ++++++++++++++     ++ ++++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:105:17
+   |
+LL |         let _ = a.gt(&b);
+   |                 ^^^^^^^^
+   |
+help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+   |
+LL |         let _ = (*a).cast::<()>().gt(&(*b).cast::<()>());
+   |                 ++ ++++++++++++++     ++ ++++++++++++++
+
+warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+  --> $DIR/wide_pointer_comparisons.rs:110:13
    |
 LL |     let _ = s == s;
    |             ^^^^^^
@@ -257,7 +422,7 @@ LL |     let _ = std::ptr::eq(s, s);
    |             +++++++++++++ ~  +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:78:13
+  --> $DIR/wide_pointer_comparisons.rs:114:13
    |
 LL |     let _ = s == s;
    |             ^^^^^^
@@ -272,7 +437,7 @@ LL |     let _ = std::ptr::eq(s, s);
    |             +++++++++++++ ~  +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:82:17
+  --> $DIR/wide_pointer_comparisons.rs:118:17
    |
 LL |         let _ = a == b;
    |                 ^^^^^^
@@ -287,7 +452,7 @@ LL |         let _ = std::ptr::eq(a, b);
    |                 +++++++++++++ ~  +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:84:17
+  --> $DIR/wide_pointer_comparisons.rs:120:17
    |
 LL |         let _ = a != b;
    |                 ^^^^^^
@@ -302,51 +467,51 @@ LL |         let _ = !std::ptr::eq(a, b);
    |                 ++++++++++++++ ~  +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:86:17
+  --> $DIR/wide_pointer_comparisons.rs:122:17
    |
 LL |         let _ = a < b;
    |                 ^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |         let _ = a as *const () < b as *const ();
-   |                   ++++++++++++     ++++++++++++
+LL |         let _ = a.cast::<()>() < b.cast::<()>();
+   |                  +++++++++++++    +++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:88:17
+  --> $DIR/wide_pointer_comparisons.rs:124:17
    |
 LL |         let _ = a <= b;
    |                 ^^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |         let _ = a as *const () <= b as *const ();
-   |                   ++++++++++++      ++++++++++++
+LL |         let _ = a.cast::<()>() <= b.cast::<()>();
+   |                  +++++++++++++     +++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:90:17
+  --> $DIR/wide_pointer_comparisons.rs:126:17
    |
 LL |         let _ = a > b;
    |                 ^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |         let _ = a as *const () > b as *const ();
-   |                   ++++++++++++     ++++++++++++
+LL |         let _ = a.cast::<()>() > b.cast::<()>();
+   |                  +++++++++++++    +++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:92:17
+  --> $DIR/wide_pointer_comparisons.rs:128:17
    |
 LL |         let _ = a >= b;
    |                 ^^^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |         let _ = a as *const () >= b as *const ();
-   |                   ++++++++++++      ++++++++++++
+LL |         let _ = a.cast::<()>() >= b.cast::<()>();
+   |                  +++++++++++++     +++++++++++++
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:95:17
+  --> $DIR/wide_pointer_comparisons.rs:131:17
    |
 LL |         let _ = PartialEq::eq(&a, &b);
    |                 ^^^^^^^^^^^^^^^^^^^^^
@@ -361,7 +526,7 @@ LL |         let _ = std::ptr::eq(a, b);
    |                 ~~~~~~~~~~~~~ ~  ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:97:17
+  --> $DIR/wide_pointer_comparisons.rs:133:17
    |
 LL |         let _ = PartialEq::ne(&a, &b);
    |                 ^^^^^^^^^^^^^^^^^^^^^
@@ -376,7 +541,7 @@ LL |         let _ = !std::ptr::eq(a, b);
    |                 ~~~~~~~~~~~~~~ ~  ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:99:17
+  --> $DIR/wide_pointer_comparisons.rs:135:17
    |
 LL |         let _ = a.eq(&b);
    |                 ^^^^^^^^
@@ -391,7 +556,7 @@ LL |         let _ = std::ptr::eq(a, b);
    |                 +++++++++++++ ~  ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:101:17
+  --> $DIR/wide_pointer_comparisons.rs:137:17
    |
 LL |         let _ = a.ne(&b);
    |                 ^^^^^^^^
@@ -406,7 +571,7 @@ LL |         let _ = !std::ptr::eq(a, b);
    |                 ++++++++++++++ ~  ~
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:106:9
+  --> $DIR/wide_pointer_comparisons.rs:142:9
    |
 LL |         &*a == &*b
    |         ^^^^^^^^^^
@@ -421,7 +586,7 @@ LL |         std::ptr::eq(*a, *b)
    |         ~~~~~~~~~~~~~  ~   +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:117:14
+  --> $DIR/wide_pointer_comparisons.rs:153:14
    |
 LL |         cmp!(a, b);
    |              ^^^^
@@ -432,7 +597,7 @@ LL |         cmp!(std::ptr::addr_eq(a, b));
    |              ++++++++++++++++++ ~  +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:123:39
+  --> $DIR/wide_pointer_comparisons.rs:159:39
    |
 LL |             ($a:ident, $b:ident) => { $a == $b }
    |                                       ^^^^^^^^
@@ -447,7 +612,7 @@ LL |             ($a:ident, $b:ident) => { std::ptr::addr_eq($a, $b) }
    |                                       ++++++++++++++++++  ~   +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:133:37
+  --> $DIR/wide_pointer_comparisons.rs:169:37
    |
 LL |             ($a:expr, $b:expr) => { $a == $b }
    |                                     ^^
@@ -459,5 +624,5 @@ LL |         cmp!(&a, &b);
    = help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    = note: this warning originates in the macro `cmp` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: 38 warnings emitted
+warning: 53 warnings emitted
 
diff --git a/tests/ui/issues/issue-1962.fixed b/tests/ui/loops/issue-1962.fixed
index f0002be4bea..f0002be4bea 100644
--- a/tests/ui/issues/issue-1962.fixed
+++ b/tests/ui/loops/issue-1962.fixed
diff --git a/tests/ui/issues/issue-1962.rs b/tests/ui/loops/issue-1962.rs
index 9c8fb500ba3..9c8fb500ba3 100644
--- a/tests/ui/issues/issue-1962.rs
+++ b/tests/ui/loops/issue-1962.rs
diff --git a/tests/ui/issues/issue-1962.stderr b/tests/ui/loops/issue-1962.stderr
index db235d47303..db235d47303 100644
--- a/tests/ui/issues/issue-1962.stderr
+++ b/tests/ui/loops/issue-1962.stderr
diff --git a/tests/ui/issues/issue-1974.rs b/tests/ui/loops/issue-1974.rs
index ea67b2541de..ea67b2541de 100644
--- a/tests/ui/issues/issue-1974.rs
+++ b/tests/ui/loops/issue-1974.rs
diff --git a/tests/ui/marker_trait_attr/unsound-overlap.rs b/tests/ui/marker_trait_attr/unsound-overlap.rs
index 2e5101b822c..2ce26b610f6 100644
--- a/tests/ui/marker_trait_attr/unsound-overlap.rs
+++ b/tests/ui/marker_trait_attr/unsound-overlap.rs
@@ -8,6 +8,7 @@ trait B {}
 impl<T: A> B for T {}
 impl<T: B> A for T {}
 impl A for &str {}
+//~^ ERROR type annotations needed: cannot satisfy `&str: A`
 impl<T: A + B> A for (T,) {}
 trait TraitWithAssoc {
     type Assoc;
diff --git a/tests/ui/marker_trait_attr/unsound-overlap.stderr b/tests/ui/marker_trait_attr/unsound-overlap.stderr
index 5e58f5227ed..13498fa4b22 100644
--- a/tests/ui/marker_trait_attr/unsound-overlap.stderr
+++ b/tests/ui/marker_trait_attr/unsound-overlap.stderr
@@ -1,5 +1,19 @@
+error[E0283]: type annotations needed: cannot satisfy `&str: A`
+  --> $DIR/unsound-overlap.rs:10:12
+   |
+LL | impl A for &str {}
+   |            ^^^^
+   |
+note: multiple `impl`s satisfying `&str: A` found
+  --> $DIR/unsound-overlap.rs:9:1
+   |
+LL | impl<T: B> A for T {}
+   | ^^^^^^^^^^^^^^^^^^
+LL | impl A for &str {}
+   | ^^^^^^^^^^^^^^^
+
 error[E0119]: conflicting implementations of trait `TraitWithAssoc` for type `((&str,),)`
-  --> $DIR/unsound-overlap.rs:20:1
+  --> $DIR/unsound-overlap.rs:21:1
    |
 LL | impl<T: A> TraitWithAssoc for T {
    | ------------------------------- first implementation here
@@ -7,6 +21,7 @@ LL | impl<T: A> TraitWithAssoc for T {
 LL | impl TraitWithAssoc for ((&str,),) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `((&str,),)`
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0119`.
+Some errors have detailed explanations: E0119, E0283.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/match/postfix-match/match-after-as.rs b/tests/ui/match/postfix-match/match-after-as.rs
new file mode 100644
index 00000000000..7c648bfcf03
--- /dev/null
+++ b/tests/ui/match/postfix-match/match-after-as.rs
@@ -0,0 +1,7 @@
+#![feature(postfix_match)]
+
+fn main() {
+    1 as i32.match {};
+    //~^ ERROR cast cannot be followed by a postfix match
+    //~| ERROR non-exhaustive patterns
+}
diff --git a/tests/ui/match/postfix-match/match-after-as.stderr b/tests/ui/match/postfix-match/match-after-as.stderr
new file mode 100644
index 00000000000..68e4762b8d9
--- /dev/null
+++ b/tests/ui/match/postfix-match/match-after-as.stderr
@@ -0,0 +1,28 @@
+error: cast cannot be followed by a postfix match
+  --> $DIR/match-after-as.rs:4:5
+   |
+LL |     1 as i32.match {};
+   |     ^^^^^^^^
+   |
+help: try surrounding the expression in parentheses
+   |
+LL |     (1 as i32).match {};
+   |     +        +
+
+error[E0004]: non-exhaustive patterns: type `i32` is non-empty
+  --> $DIR/match-after-as.rs:4:5
+   |
+LL |     1 as i32.match {};
+   |     ^^^^^^^^
+   |
+   = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     1 as i32.match {
+LL +         _ => todo!(),
+LL ~     };
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/methods/probe-overflow-due-to-sized-predicate-ordering.rs b/tests/ui/methods/probe-overflow-due-to-sized-predicate-ordering.rs
new file mode 100644
index 00000000000..08e15117c4b
--- /dev/null
+++ b/tests/ui/methods/probe-overflow-due-to-sized-predicate-ordering.rs
@@ -0,0 +1,30 @@
+//@ check-pass
+// Regression test due to #123279
+
+pub trait Job: AsJob {
+    fn run_once(&self);
+}
+
+impl<F: Fn()> Job for F {
+    fn run_once(&self) {
+        todo!()
+    }
+}
+
+pub trait AsJob {}
+
+// Ensure that `T: Sized + Job` by reordering the explicit `Sized` to where
+// the implicit sized pred would go.
+impl<T: Job + Sized> AsJob for T {}
+
+pub struct LoopingJobService {
+    job: Box<dyn Job>,
+}
+
+impl Job for LoopingJobService {
+    fn run_once(&self) {
+        self.job.run_once()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/mir/alignment/packed.rs b/tests/ui/mir/alignment/packed.rs
index fe8ecc668b8..1a12425f11a 100644
--- a/tests/ui/mir/alignment/packed.rs
+++ b/tests/ui/mir/alignment/packed.rs
@@ -1,7 +1,7 @@
 //@ run-pass
 //@ compile-flags: -C debug-assertions
 
-#![feature(strict_provenance, pointer_is_aligned)]
+#![feature(strict_provenance)]
 
 #[repr(packed)]
 struct Misaligner {
diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr
index 3585587ed4c..f8047c8e2d4 100644
--- a/tests/ui/mismatched_types/binops.stderr
+++ b/tests/ui/mismatched_types/binops.stderr
@@ -73,15 +73,15 @@ LL |     5 < String::new();
    |
    = help: the trait `PartialOrd<String>` is not implemented for `{integer}`
    = help: the following other types implement trait `PartialOrd<Rhs>`:
+             f128
+             f16
              f32
              f64
              i128
              i16
              i32
              i64
-             i8
-             isize
-           and 6 others
+           and 8 others
 
 error[E0277]: can't compare `{integer}` with `Result<{integer}, _>`
   --> $DIR/binops.rs:7:7
@@ -91,15 +91,15 @@ LL |     6 == Ok(1);
    |
    = help: the trait `PartialEq<Result<{integer}, _>>` is not implemented for `{integer}`
    = help: the following other types implement trait `PartialEq<Rhs>`:
+             f128
+             f16
              f32
              f64
              i128
              i16
              i32
              i64
-             i8
-             isize
-           and 6 others
+           and 8 others
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs
new file mode 100644
index 00000000000..2bd10e762d9
--- /dev/null
+++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs
@@ -0,0 +1,14 @@
+fn foo<T>(a: T, b: T) {}
+fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+fn foo_multi_generics<S, T>(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {}
+
+fn main() {
+    foo(1, 2.);
+    //~^  ERROR mismatched types
+    foo_multi_same("a", "b", false, true, (), 32);
+    //~^  ERROR arguments to this function are incorrect
+    foo_multi_generics("a", "b", "c", true, false, 32, 2.);
+    //~^  ERROR arguments to this function are incorrect
+    foo_multi_same("a", 1, 2, "d", "e", 32);
+    //~^  ERROR arguments to this function are incorrect
+}
diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr
new file mode 100644
index 00000000000..a845dfabe93
--- /dev/null
+++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr
@@ -0,0 +1,97 @@
+error[E0308]: mismatched types
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:6:12
+   |
+LL |     foo(1, 2.);
+   |     --- -  ^^ expected integer, found floating-point number
+   |     |   |
+   |     |   expected all arguments to be this integer type because they need to match the type of this parameter
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:1:4
+   |
+LL | fn foo<T>(a: T, b: T) {}
+   |    ^^^ -  ----  ---- this parameter needs to match the integer type of `a`
+   |        |  |
+   |        |  `b` needs to match the integer type of this parameter
+   |        `a` and `b` all reference this parameter T
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:8:5
+   |
+LL |     foo_multi_same("a", "b", false, true, (), 32);
+   |     ^^^^^^^^^^^^^^ ---  ---  -----  ----  -- expected `&str`, found `()`
+   |                    |    |    |      |
+   |                    |    |    |      expected `&str`, found `bool`
+   |                    |    |    expected `&str`, found `bool`
+   |                    |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:2:4
+   |
+LL | fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+   |    ^^^^^^^^^^^^^^ -  ----  ----  ----  ----  ----  ------
+   |                   |  |     |     |     |     |
+   |                   |  |     |     |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     `c`, `d` and `e` need to match the `&str` type of this parameter
+   |                   |  `c`, `d` and `e` need to match the `&str` type of this parameter
+   |                   `a`, `b`, `c`, `d` and `e` all reference this parameter T
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:10:5
+   |
+LL |     foo_multi_generics("a", "b", "c", true, false, 32, 2.);
+   |     ^^^^^^^^^^^^^^^^^^ ---  ---  ---  ----  -----  --  -- expected integer, found floating-point number
+   |                        |    |    |    |     |      |
+   |                        |    |    |    |     |      expected some other arguments to be an integer type to match the type of this parameter
+   |                        |    |    |    |     expected `&str`, found `bool`
+   |                        |    |    |    expected `&str`, found `bool`
+   |                        |    |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                        |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                        expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:3:4
+   |
+LL | fn foo_multi_generics<S, T>(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {}
+   |    ^^^^^^^^^^^^^^^^^^ -  -  ----  ----  ----  ----  ----  ----  ---- this parameter needs to match the integer type of `f`
+   |                       |  |  |     |     |     |     |     |
+   |                       |  |  |     |     |     |     |     `g` needs to match the integer type of this parameter
+   |                       |  |  |     |     |     |     this parameter needs to match the `&str` type of `a`, `b` and `c`
+   |                       |  |  |     |     |     this parameter needs to match the `&str` type of `a`, `b` and `c`
+   |                       |  |  |     |     `d` and `e` need to match the `&str` type of this parameter
+   |                       |  |  |     `d` and `e` need to match the `&str` type of this parameter
+   |                       |  |  `d` and `e` need to match the `&str` type of this parameter
+   |                       |  `a`, `b`, `c`, `d` and `e` all reference this parameter T
+   |                       `f` and `g` all reference this parameter S
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:12:5
+   |
+LL |     foo_multi_same("a", 1, 2, "d", "e", 32);
+   |     ^^^^^^^^^^^^^^ ---  -  -  ---  --- expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    |    |  |  |
+   |                    |    |  |  expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    |    |  expected `&str`, found integer
+   |                    |    expected `&str`, found integer
+   |                    expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:2:4
+   |
+LL | fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+   |    ^^^^^^^^^^^^^^ -  ----  ----  ----  ----  ----  ------
+   |                   |  |     |     |     |     |
+   |                   |  |     |     |     |     `b` and `c` need to match the `&str` type of this parameter
+   |                   |  |     |     |     `b` and `c` need to match the `&str` type of this parameter
+   |                   |  |     |     this parameter needs to match the `&str` type of `a`, `d` and `e`
+   |                   |  |     this parameter needs to match the `&str` type of `a`, `d` and `e`
+   |                   |  `b` and `c` need to match the `&str` type of this parameter
+   |                   `a`, `b`, `c`, `d` and `e` all reference this parameter T
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/issues/issue-1362.rs b/tests/ui/mismatched_types/issue-1362.rs
index 6fd43f50e4d..6fd43f50e4d 100644
--- a/tests/ui/issues/issue-1362.rs
+++ b/tests/ui/mismatched_types/issue-1362.rs
diff --git a/tests/ui/issues/issue-1362.stderr b/tests/ui/mismatched_types/issue-1362.stderr
index 6f6fdff6678..6f6fdff6678 100644
--- a/tests/ui/issues/issue-1362.stderr
+++ b/tests/ui/mismatched_types/issue-1362.stderr
diff --git a/tests/ui/issues/issue-1448-2.rs b/tests/ui/mismatched_types/issue-1448-2.rs
index 829e81b9c24..829e81b9c24 100644
--- a/tests/ui/issues/issue-1448-2.rs
+++ b/tests/ui/mismatched_types/issue-1448-2.rs
diff --git a/tests/ui/issues/issue-1448-2.stderr b/tests/ui/mismatched_types/issue-1448-2.stderr
index a6f1daefe63..a6f1daefe63 100644
--- a/tests/ui/issues/issue-1448-2.stderr
+++ b/tests/ui/mismatched_types/issue-1448-2.stderr
diff --git a/tests/ui/nll/match-cfg-fake-edges.rs b/tests/ui/nll/match-cfg-fake-edges.rs
index 1afc7931a6b..e349c2c8e2a 100644
--- a/tests/ui/nll/match-cfg-fake-edges.rs
+++ b/tests/ui/nll/match-cfg-fake-edges.rs
@@ -3,10 +3,46 @@
 
 #![feature(if_let_guard)]
 
+#[rustfmt::skip]
+fn all_patterns_are_tested() {
+    // Even though `x` is never actually moved out of, we don't want borrowck results to be based on
+    // whether MIR lowering reveals which patterns are unreachable.
+    let x = String::new();
+    match true {
+        _ => {},
+        _ => drop(x),
+    }
+    // Borrowck must not know the second arm is never run.
+    drop(x); //~ ERROR use of moved value
+
+    let x = String::new();
+    if let _ = true { //~ WARN irrefutable
+    } else {
+        drop(x)
+    }
+    // Borrowck must not know the else branch is never run.
+    drop(x); //~ ERROR use of moved value
+
+    let x = (String::new(), String::new());
+    match x {
+        (y, _) | (_, y) => (),
+    }
+    &x.0; //~ ERROR borrow of moved value
+    // Borrowck must not know the second pattern never matches.
+    &x.1; //~ ERROR borrow of moved value
+
+    let x = (String::new(), String::new());
+    let ((y, _) | (_, y)) = x;
+    &x.0; //~ ERROR borrow of moved value
+    // Borrowck must not know the second pattern never matches.
+    &x.1; //~ ERROR borrow of moved value
+}
+
+#[rustfmt::skip]
 fn guard_always_precedes_arm(y: i32) {
-    let mut x;
     // x should always be initialized, as the only way to reach the arm is
     // through the guard.
+    let mut x;
     match y {
         0 | 2 if { x = 2; true } => x,
         _ => 2,
@@ -14,56 +50,69 @@ fn guard_always_precedes_arm(y: i32) {
 
     let mut x;
     match y {
+        _ => 2,
+        0 | 2 if { x = 2; true } => x,
+    };
+
+    let mut x;
+    match y {
         0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
         _ => 2,
     };
 }
 
+#[rustfmt::skip]
 fn guard_may_be_skipped(y: i32) {
+    // Even though x *is* always initialized, we don't want to have borrowck results be based on
+    // whether MIR lowering reveals which patterns are exhaustive.
+    let x;
+    match y {
+        _ if { x = 2; true } => {},
+        // Borrowck must not know the guard is always run.
+        _ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized
+    };
+
     let x;
-    // Even though x *is* always initialized, we don't want to have borrowck
-    // results be based on whether patterns are exhaustive.
     match y {
         _ if { x = 2; true } => 1,
-        _ if {
-            x; //~ ERROR E0381
-            false
-        } => 2,
+        // Borrowck must not know the guard is always run.
+        _ if { x; false } => 2, //~ ERROR used binding `x` isn't initialized
         _ => 3,
     };
 
     let x;
     match y {
         _ if let Some(()) = { x = 2; Some(()) } => 1,
-        _ if let Some(()) = {
-            x; //~ ERROR E0381
-            None
-        } => 2,
+        _ if let Some(()) = { x; None } => 2, //~ ERROR used binding `x` isn't initialized
         _ => 3,
     };
 }
 
+#[rustfmt::skip]
 fn guard_may_be_taken(y: bool) {
-    let x = String::new();
     // Even though x *is* never moved before the use, we don't want to have
     // borrowck results be based on whether patterns are disjoint.
+    let x = String::new();
+    match y {
+        false if { drop(x); true } => {},
+        // Borrowck must not know the guard is not run in the `true` case.
+        true => drop(x), //~ ERROR use of moved value: `x`
+        false => {},
+    };
+
+    // Fine in the other order.
+    let x = String::new();
     match y {
-        false if { drop(x); true } => 1,
-        true => {
-            x; //~ ERROR use of moved value: `x`
-            2
-        }
-        false => 3,
+        true => drop(x),
+        false if { drop(x); true } => {},
+        false => {},
     };
 
     let x = String::new();
     match y {
-        false if let Some(()) = { drop(x); Some(()) } => 1,
-        true => {
-            x; //~ ERROR use of moved value: `x`
-            2
-        }
-        false => 3,
+        false if let Some(()) = { drop(x); Some(()) } => {},
+        true => drop(x), //~ ERROR use of moved value: `x`
+        false => {},
     };
 }
 
diff --git a/tests/ui/nll/match-cfg-fake-edges.stderr b/tests/ui/nll/match-cfg-fake-edges.stderr
index a6261345cea..d692ded36fa 100644
--- a/tests/ui/nll/match-cfg-fake-edges.stderr
+++ b/tests/ui/nll/match-cfg-fake-edges.stderr
@@ -1,14 +1,128 @@
-error[E0381]: used binding `x` isn't initialized
-  --> $DIR/match-cfg-fake-edges.rs:29:13
+warning: irrefutable `if let` pattern
+  --> $DIR/match-cfg-fake-edges.rs:19:8
+   |
+LL |     if let _ = true {
+   |        ^^^^^^^^^^^^
+   |
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
+   = note: `#[warn(irrefutable_let_patterns)]` on by default
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/match-cfg-fake-edges.rs:16:10
+   |
+LL |     let x = String::new();
+   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+...
+LL |         _ => drop(x),
+   |                   - value moved here
+...
+LL |     drop(x);
+   |          ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         _ => drop(x.clone()),
+   |                    ++++++++
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/match-cfg-fake-edges.rs:24:10
+   |
+LL |     let x = String::new();
+   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+...
+LL |         drop(x)
+   |              - value moved here
+...
+LL |     drop(x);
+   |          ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         drop(x.clone())
+   |               ++++++++
+
+error[E0382]: borrow of moved value: `x.0`
+  --> $DIR/match-cfg-fake-edges.rs:30:5
+   |
+LL |         (y, _) | (_, y) => (),
+   |          - value moved here
+LL |     }
+LL |     &x.0;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         (ref y, _) | (_, y) => (),
+   |          +++
+
+error[E0382]: borrow of moved value: `x.1`
+  --> $DIR/match-cfg-fake-edges.rs:32:5
+   |
+LL |         (y, _) | (_, y) => (),
+   |                      - value moved here
+...
+LL |     &x.1;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         (y, _) | (_, ref y) => (),
+   |                      +++
+
+error[E0382]: borrow of moved value: `x.0`
+  --> $DIR/match-cfg-fake-edges.rs:36:5
+   |
+LL |     let ((y, _) | (_, y)) = x;
+   |           - value moved here
+LL |     &x.0;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((ref y, _) | (_, y)) = x;
+   |           +++
+
+error[E0382]: borrow of moved value: `x.1`
+  --> $DIR/match-cfg-fake-edges.rs:38:5
+   |
+LL |     let ((y, _) | (_, y)) = x;
+   |                       - value moved here
+...
+LL |     &x.1;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((y, _) | (_, ref y)) = x;
+   |                       +++
+
+error[E0381]: used binding `x` is possibly-uninitialized
+  --> $DIR/match-cfg-fake-edges.rs:72:19
    |
 LL |     let x;
    |         - binding declared here but left uninitialized
 ...
+LL |         _ => drop(x),
+   |         -         ^ `x` used here but it is possibly-uninitialized
+   |         |
+   |         if this pattern is matched, `x` is not initialized
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/match-cfg-fake-edges.rs:79:16
+   |
+LL |     let x;
+   |         - binding declared here but left uninitialized
+LL |     match y {
 LL |         _ if { x = 2; true } => 1,
    |                ----- binding initialized here in some conditions
-LL |         _ if {
-LL |             x;
-   |             ^ `x` used here but it isn't initialized
+LL |         // Borrowck must not know the guard is always run.
+LL |         _ if { x; false } => 2,
+   |                ^ `x` used here but it isn't initialized
    |
 help: consider assigning a value
    |
@@ -16,16 +130,15 @@ LL |     let x = 0;
    |           +++
 
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/match-cfg-fake-edges.rs:39:13
+  --> $DIR/match-cfg-fake-edges.rs:86:31
    |
 LL |     let x;
    |         - binding declared here but left uninitialized
 LL |     match y {
 LL |         _ if let Some(()) = { x = 2; Some(()) } => 1,
    |                               ----- binding initialized here in some conditions
-LL |         _ if let Some(()) = {
-LL |             x;
-   |             ^ `x` used here but it isn't initialized
+LL |         _ if let Some(()) = { x; None } => 2,
+   |                               ^ `x` used here but it isn't initialized
    |
 help: consider assigning a value
    |
@@ -33,40 +146,39 @@ LL |     let x = 0;
    |           +++
 
 error[E0382]: use of moved value: `x`
-  --> $DIR/match-cfg-fake-edges.rs:53:13
+  --> $DIR/match-cfg-fake-edges.rs:99:22
    |
 LL |     let x = String::new();
    |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
-...
-LL |         false if { drop(x); true } => 1,
+LL |     match y {
+LL |         false if { drop(x); true } => {},
    |                         - value moved here
-LL |         true => {
-LL |             x;
-   |             ^ value used here after move
+LL |         // Borrowck must not know the guard is not run in the `true` case.
+LL |         true => drop(x),
+   |                      ^ value used here after move
    |
 help: consider cloning the value if the performance cost is acceptable
    |
-LL |         false if { drop(x.clone()); true } => 1,
+LL |         false if { drop(x.clone()); true } => {},
    |                          ++++++++
 
 error[E0382]: use of moved value: `x`
-  --> $DIR/match-cfg-fake-edges.rs:63:13
+  --> $DIR/match-cfg-fake-edges.rs:114:22
    |
 LL |     let x = String::new();
    |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
 LL |     match y {
-LL |         false if let Some(()) = { drop(x); Some(()) } => 1,
+LL |         false if let Some(()) = { drop(x); Some(()) } => {},
    |                                        - value moved here
-LL |         true => {
-LL |             x;
-   |             ^ value used here after move
+LL |         true => drop(x),
+   |                      ^ value used here after move
    |
 help: consider cloning the value if the performance cost is acceptable
    |
-LL |         false if let Some(()) = { drop(x.clone()); Some(()) } => 1,
+LL |         false if let Some(()) = { drop(x.clone()); Some(()) } => {},
    |                                         ++++++++
 
-error: aborting due to 4 previous errors
+error: aborting due to 11 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0381, E0382.
 For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/nll/match-cfg-fake-edges2.rs b/tests/ui/nll/match-cfg-fake-edges2.rs
index 48f95e03b78..ac90fb9cd1e 100644
--- a/tests/ui/nll/match-cfg-fake-edges2.rs
+++ b/tests/ui/nll/match-cfg-fake-edges2.rs
@@ -5,13 +5,20 @@ fn all_previous_tests_may_be_done(y: &mut (bool, bool)) {
     let r = &mut y.1;
     // We don't actually test y.1 to select the second arm, but we don't want
     // borrowck results to be based on the order we match patterns.
-    match y { //~ ERROR cannot use `y.1` because it was mutably borrowed
-        (false, true) => 1,
-        (true, _) => {
-            r;
-            2
-        }
-        (false, _) => 3,
+    match y {
+        //~^ ERROR cannot use `y.1` because it was mutably borrowed
+        (false, true) => {}
+        // Borrowck must not know we don't test `y.1` when `y.0` is `true`.
+        (true, _) => drop(r),
+        (false, _) => {}
+    };
+
+    // Fine in the other order.
+    let r = &mut y.1;
+    match y {
+        (true, _) => drop(r),
+        (false, true) => {}
+        (false, _) => {}
     };
 }
 
diff --git a/tests/ui/nll/match-cfg-fake-edges2.stderr b/tests/ui/nll/match-cfg-fake-edges2.stderr
index 639cba1406a..0a228d62b92 100644
--- a/tests/ui/nll/match-cfg-fake-edges2.stderr
+++ b/tests/ui/nll/match-cfg-fake-edges2.stderr
@@ -7,8 +7,8 @@ LL |     let r = &mut y.1;
 LL |     match y {
    |     ^^^^^^^ use of borrowed `y.1`
 ...
-LL |             r;
-   |             - borrow later used here
+LL |         (true, _) => drop(r),
+   |                           - borrow later used here
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/pattern/usefulness/unions.rs b/tests/ui/pattern/usefulness/unions.rs
new file mode 100644
index 00000000000..80a7f36a09a
--- /dev/null
+++ b/tests/ui/pattern/usefulness/unions.rs
@@ -0,0 +1,35 @@
+fn main() {
+    #[derive(Copy, Clone)]
+    union U8AsBool {
+        n: u8,
+        b: bool,
+    }
+
+    let x = U8AsBool { n: 1 };
+    unsafe {
+        match x {
+            // exhaustive
+            U8AsBool { n: 2 } => {}
+            U8AsBool { b: true } => {}
+            U8AsBool { b: false } => {}
+        }
+        match x {
+            // exhaustive
+            U8AsBool { b: true } => {}
+            U8AsBool { n: 0 } => {}
+            U8AsBool { n: 1.. } => {}
+        }
+        match x {
+            //~^ ERROR non-exhaustive patterns: `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered
+            U8AsBool { b: true } => {}
+            U8AsBool { n: 1.. } => {}
+        }
+        // Our approach can report duplicate witnesses sometimes.
+        match (x, true) {
+            //~^ ERROR non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered
+            (U8AsBool { b: true }, true) => {}
+            (U8AsBool { b: false }, true) => {}
+            (U8AsBool { n: 1.. }, true) => {}
+        }
+    }
+}
diff --git a/tests/ui/pattern/usefulness/unions.stderr b/tests/ui/pattern/usefulness/unions.stderr
new file mode 100644
index 00000000000..4b397dc25db
--- /dev/null
+++ b/tests/ui/pattern/usefulness/unions.stderr
@@ -0,0 +1,34 @@
+error[E0004]: non-exhaustive patterns: `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered
+  --> $DIR/unions.rs:22:15
+   |
+LL |         match x {
+   |               ^ patterns `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered
+   |
+note: `U8AsBool` defined here
+  --> $DIR/unions.rs:3:11
+   |
+LL |     union U8AsBool {
+   |           ^^^^^^^^
+   = note: the matched value is of type `U8AsBool`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~             U8AsBool { n: 1.. } => {},
+LL +             U8AsBool { n: 0_u8 } | U8AsBool { b: false } => todo!()
+   |
+
+error[E0004]: non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered
+  --> $DIR/unions.rs:28:15
+   |
+LL |         match (x, true) {
+   |               ^^^^^^^^^ patterns `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered
+   |
+   = note: the matched value is of type `(U8AsBool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~             (U8AsBool { n: 1.. }, true) => {},
+LL +             _ => todo!()
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/proc-macro/bad-projection.rs b/tests/ui/proc-macro/bad-projection.rs
index e633191bd31..0769a7f08c1 100644
--- a/tests/ui/proc-macro/bad-projection.rs
+++ b/tests/ui/proc-macro/bad-projection.rs
@@ -15,4 +15,5 @@ pub fn uwu() -> <() as Project>::Assoc {}
 //~^ ERROR the trait bound `(): Project` is not satisfied
 //~| ERROR the trait bound `(): Project` is not satisfied
 //~| ERROR the trait bound `(): Project` is not satisfied
+//~| ERROR the trait bound `(): Project` is not satisfied
 //~| ERROR function is expected to take 1 argument, but it takes 0 arguments
diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr
index 8e0d8461849..2e8668f60de 100644
--- a/tests/ui/proc-macro/bad-projection.stderr
+++ b/tests/ui/proc-macro/bad-projection.stderr
@@ -36,6 +36,18 @@ LL | trait Project {
    | ^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `(): Project` is not satisfied
+  --> $DIR/bad-projection.rs:14:1
+   |
+LL | pub fn uwu() -> <() as Project>::Assoc {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/bad-projection.rs:9:1
+   |
+LL | trait Project {
+   | ^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `(): Project` is not satisfied
   --> $DIR/bad-projection.rs:14:40
    |
 LL | pub fn uwu() -> <() as Project>::Assoc {}
@@ -47,7 +59,7 @@ help: this trait has no implementations, consider adding one
 LL | trait Project {
    | ^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0277, E0593.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/repr/repr-align.rs b/tests/ui/repr/repr-align.rs
index 58ecf9a5183..33aa727d4bd 100644
--- a/tests/ui/repr/repr-align.rs
+++ b/tests/ui/repr/repr-align.rs
@@ -15,6 +15,10 @@ struct S2(i32);
 #[repr(align(536870912))] // ok: this is the largest accepted alignment
 struct S3(i32);
 
+#[repr(align(0))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
+                  //~| ERROR: invalid `repr(align)` attribute: not a power of two
+struct S4(i32);
+
 #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
                      //~| ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
 enum E0 { A, B }
@@ -30,4 +34,8 @@ enum E2 { A, B }
 #[repr(align(536870912))] // ok: this is the largest accepted alignment
 enum E3 { A, B }
 
+#[repr(align(0))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
+                  //~| ERROR: invalid `repr(align)` attribute: not a power of two
+enum E4 { A, B }
+
 fn main() {}
diff --git a/tests/ui/repr/repr-align.stderr b/tests/ui/repr/repr-align.stderr
index bb0e17ba395..660247840c4 100644
--- a/tests/ui/repr/repr-align.stderr
+++ b/tests/ui/repr/repr-align.stderr
@@ -16,24 +16,36 @@ error[E0589]: invalid `repr(align)` attribute: larger than 2^29
 LL | #[repr(align(4294967296))]
    |              ^^^^^^^^^^
 
-error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
+error[E0589]: invalid `repr(align)` attribute: not a power of two
   --> $DIR/repr-align.rs:18:14
    |
+LL | #[repr(align(0))]
+   |              ^
+
+error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
+  --> $DIR/repr-align.rs:22:14
+   |
 LL | #[repr(align(16.0))]
    |              ^^^^
 
 error[E0589]: invalid `repr(align)` attribute: not a power of two
-  --> $DIR/repr-align.rs:22:14
+  --> $DIR/repr-align.rs:26:14
    |
 LL | #[repr(align(15))]
    |              ^^
 
 error[E0589]: invalid `repr(align)` attribute: larger than 2^29
-  --> $DIR/repr-align.rs:26:14
+  --> $DIR/repr-align.rs:30:14
    |
 LL | #[repr(align(4294967296))]
    |              ^^^^^^^^^^
 
+error[E0589]: invalid `repr(align)` attribute: not a power of two
+  --> $DIR/repr-align.rs:37:14
+   |
+LL | #[repr(align(0))]
+   |              ^
+
 error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
   --> $DIR/repr-align.rs:3:14
    |
@@ -58,16 +70,24 @@ LL | #[repr(align(4294967296))]
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
+error[E0589]: invalid `repr(align)` attribute: not a power of two
   --> $DIR/repr-align.rs:18:14
    |
+LL | #[repr(align(0))]
+   |              ^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
+  --> $DIR/repr-align.rs:22:14
+   |
 LL | #[repr(align(16.0))]
    |              ^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0589]: invalid `repr(align)` attribute: not a power of two
-  --> $DIR/repr-align.rs:22:14
+  --> $DIR/repr-align.rs:26:14
    |
 LL | #[repr(align(15))]
    |              ^^
@@ -75,13 +95,21 @@ LL | #[repr(align(15))]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0589]: invalid `repr(align)` attribute: larger than 2^29
-  --> $DIR/repr-align.rs:26:14
+  --> $DIR/repr-align.rs:30:14
    |
 LL | #[repr(align(4294967296))]
    |              ^^^^^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 12 previous errors
+error[E0589]: invalid `repr(align)` attribute: not a power of two
+  --> $DIR/repr-align.rs:37:14
+   |
+LL | #[repr(align(0))]
+   |              ^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 16 previous errors
 
 For more information about this error, try `rustc --explain E0589`.
diff --git a/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs b/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs
new file mode 100644
index 00000000000..93f51820101
--- /dev/null
+++ b/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: --crate-type=lib
+//@ check-pass
+//@ revisions: e2015 e2018
+//
+//@[e2018] edition:2018
+
+// Verify that gates for the `f16` and `f128` features do not apply to user modules
+// See <https://github.com/rust-lang/rust/issues/123282>
+
+mod f16 {
+    pub fn a16() {}
+}
+
+mod f128 {
+    pub fn a128() {}
+}
+
+pub use f128::a128;
+pub use f16::a16;
diff --git a/tests/ui/resolve/primitive-f16-f128-shadowed.rs b/tests/ui/resolve/primitive-f16-f128-shadowed.rs
index ed3fb44b256..38c7e15bf5a 100644
--- a/tests/ui/resolve/primitive-f16-f128-shadowed.rs
+++ b/tests/ui/resolve/primitive-f16-f128-shadowed.rs
@@ -1,5 +1,8 @@
 //@ compile-flags: --crate-type=lib
 //@ check-pass
+//@ revisions: e2015 e2018
+//
+//@[e2018] edition:2018
 
 // Verify that gates for the `f16` and `f128` features do not apply to user types
 
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
deleted file mode 100644
index 7bbd4e15898..00000000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/fn-ptr.rs:11:21
-   |
-LL | #[target_feature(enable = "sse2")]
-   | ---------------------------------- `#[target_feature]` added here
-...
-LL |     let foo: fn() = foo;
-   |              ----   ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers
-   |              |
-   |              expected due to this
-   |
-   = note: expected fn pointer `fn()`
-                 found fn item `fn() {foo}`
-   = note: fn items are distinct from fn pointers
-   = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
-help: consider casting to a fn pointer
-   |
-LL |     let foo: fn() = foo as fn();
-   |                     ~~~~~~~~~~~
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
deleted file mode 100644
index 7bbd4e15898..00000000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/fn-ptr.rs:11:21
-   |
-LL | #[target_feature(enable = "sse2")]
-   | ---------------------------------- `#[target_feature]` added here
-...
-LL |     let foo: fn() = foo;
-   |              ----   ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers
-   |              |
-   |              expected due to this
-   |
-   = note: expected fn pointer `fn()`
-                 found fn item `fn() {foo}`
-   = note: fn items are distinct from fn pointers
-   = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
-help: consider casting to a fn pointer
-   |
-LL |     let foo: fn() = foo as fn();
-   |                     ~~~~~~~~~~~
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
deleted file mode 100644
index cabc475fa61..00000000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
+++ /dev/null
@@ -1,115 +0,0 @@
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:28:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:31:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:34:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:41:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:44:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:51:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:54:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:57:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:65:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:70:15
-   |
-LL | const _: () = sse2();
-   |               ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:74:15
-   |
-LL | const _: () = sse2_and_fxsr();
-   |               ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr
-   = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
-
-error: call to function with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
-  --> $DIR/safe-calls.rs:82:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-note: an unsafe function restricts its caller, but its body is safe by default
-  --> $DIR/safe-calls.rs:81:1
-   |
-LL | unsafe fn needs_unsafe_block() {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: the lint level is defined here
-  --> $DIR/safe-calls.rs:78:8
-   |
-LL | #[deny(unsafe_op_in_unsafe_fn)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
deleted file mode 100644
index 13b58fde862..00000000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
+++ /dev/null
@@ -1,115 +0,0 @@
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:28:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:31:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:34:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:41:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:44:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:51:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:54:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: bmi2
-
-error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:57:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: bmi2
-
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:65:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:70:15
-   |
-LL | const _: () = sse2();
-   |               ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:74:15
-   |
-LL | const _: () = sse2_and_fxsr();
-   |               ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr
-   = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
-
-error: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
-  --> $DIR/safe-calls.rs:82:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-note: an unsafe function restricts its caller, but its body is safe by default
-  --> $DIR/safe-calls.rs:81:1
-   |
-LL | unsafe fn needs_unsafe_block() {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: the lint level is defined here
-  --> $DIR/safe-calls.rs:78:8
-   |
-LL | #[deny(unsafe_op_in_unsafe_fn)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/sanitizer/cfg.rs b/tests/ui/sanitizer/cfg.rs
index 942141bd3fe..b1ba17d5713 100644
--- a/tests/ui/sanitizer/cfg.rs
+++ b/tests/ui/sanitizer/cfg.rs
@@ -11,6 +11,7 @@
 //@[cfi]compile-flags:     -Clto -Ccodegen-units=1
 //@[kcfi]needs-llvm-components: x86
 //@[kcfi]compile-flags:    -Zsanitizer=kcfi    --cfg kcfi --target x86_64-unknown-none
+//@[kcfi]compile-flags:    -C panic=abort
 //@[leak]needs-sanitizer-leak
 //@[leak]compile-flags:    -Zsanitizer=leak    --cfg leak
 //@[memory]needs-sanitizer-memory
diff --git a/tests/ui/sanitizer/cfi-async-closures.rs b/tests/ui/sanitizer/cfi-async-closures.rs
new file mode 100644
index 00000000000..d94f2992d84
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-async-closures.rs
@@ -0,0 +1,33 @@
+// Check various forms of dynamic closure calls
+
+//@ edition: 2021
+//@ revisions: cfi kcfi
+// FIXME(#122848) Remove only-linux once OSX CFI binaries work
+//@ only-linux
+//@ [cfi] needs-sanitizer-cfi
+//@ [kcfi] needs-sanitizer-kcfi
+//@ compile-flags: -C target-feature=-crt-static
+//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
+//@ [cfi] compile-flags: -Z sanitizer=cfi
+//@ [kcfi] compile-flags: -Z sanitizer=kcfi
+//@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off
+//@ run-pass
+
+#![feature(async_closure)]
+#![feature(async_fn_traits)]
+
+use std::ops::AsyncFn;
+
+#[inline(never)]
+fn identity<T>(x: T) -> T { x }
+
+// We can't actually create a `dyn AsyncFn()`, because it's not object-safe, but we should check
+// that we don't bug out when we encounter one.
+
+fn main() {
+   let f = identity(async || ());
+   let _ = f.async_call(());
+   let _ = f();
+   let g: Box<dyn FnOnce() -> _> = Box::new(f) as _;
+   let _ = g();
+}
diff --git a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs
deleted file mode 100644
index 1ae494d87d4..00000000000
--- a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Tests that converting a closure to a function pointer works
-// The notable thing being tested here is that when the closure does not capture anything,
-// the call method from its Fn trait takes a ZST representing its environment. The compiler then
-// uses the assumption that the ZST is non-passed to reify this into a function pointer.
-//
-// This checks that the reified function pointer will have the expected alias set at its call-site.
-
-//@ revisions: cfi kcfi
-// FIXME(#122848) Remove only-linux once OSX CFI binaries work
-//@ only-linux
-//@ [cfi] needs-sanitizer-cfi
-//@ [kcfi] needs-sanitizer-kcfi
-//@ compile-flags: -C target-feature=-crt-static
-//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
-//@ [cfi] compile-flags: -Z sanitizer=cfi
-//@ [kcfi] compile-flags: -Z sanitizer=kcfi
-//@ run-pass
-
-pub fn main() {
-    let f: &fn() = &((|| ()) as _);
-    f();
-}
diff --git a/tests/ui/sanitizer/cfi-closures.rs b/tests/ui/sanitizer/cfi-closures.rs
new file mode 100644
index 00000000000..f3d9be35716
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-closures.rs
@@ -0,0 +1,79 @@
+// Check various forms of dynamic closure calls
+
+//@ revisions: cfi kcfi
+// FIXME(#122848) Remove only-linux once OSX CFI binaries work
+//@ only-linux
+//@ [cfi] needs-sanitizer-cfi
+//@ [kcfi] needs-sanitizer-kcfi
+//@ compile-flags: -C target-feature=-crt-static
+//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
+//@ [cfi] compile-flags: -Z sanitizer=cfi
+//@ [kcfi] compile-flags: -Z sanitizer=kcfi
+//@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off
+//@ compile-flags: --test
+//@ run-pass
+
+#![feature(fn_traits)]
+#![feature(unboxed_closures)]
+
+fn foo<'a, T>() -> Box<dyn Fn(&'a T) -> &'a T> {
+    Box::new(|x| x)
+}
+
+#[test]
+fn dyn_fn_with_params() {
+    let x = 3;
+    let f = foo();
+    f(&x);
+    // FIXME remove once drops are working.
+    std::mem::forget(f);
+}
+
+#[test]
+fn call_fn_trait() {
+   let f: &(dyn Fn()) = &(|| {}) as _;
+   f.call(());
+}
+
+#[test]
+fn fn_ptr_cast() {
+    let f: &fn() = &((|| ()) as _);
+    f();
+}
+
+fn use_fnmut<F: FnMut()>(mut f: F) {
+    f()
+}
+
+#[test]
+fn fn_to_fnmut() {
+    let f: &(dyn Fn()) = &(|| {}) as _;
+    use_fnmut(f);
+}
+
+fn hrtb_helper(f: &dyn for<'a> Fn(&'a usize)) {
+    f(&10)
+}
+
+#[test]
+fn hrtb_fn() {
+    hrtb_helper((&|x: &usize| println!("{}", *x)) as _)
+}
+
+#[test]
+fn fnonce() {
+    let f: Box<dyn FnOnce()> = Box::new(|| {}) as _;
+    f();
+}
+
+fn use_closure<C>(call: extern "rust-call" fn(&C, ()) -> i32, f: &C) -> i32 {
+    call(f, ())
+}
+
+#[test]
+fn closure_addr_taken() {
+    let x = 3i32;
+    let f = || x;
+    let call = Fn::<()>::call;
+    use_closure(call, &f);
+}
diff --git a/tests/ui/sanitizer/cfi-complex-receiver.rs b/tests/ui/sanitizer/cfi-complex-receiver.rs
index 52095a384b2..c7b45a775ca 100644
--- a/tests/ui/sanitizer/cfi-complex-receiver.rs
+++ b/tests/ui/sanitizer/cfi-complex-receiver.rs
@@ -11,6 +11,7 @@
 //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
+//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
 //@ run-pass
 
 use std::sync::Arc;
diff --git a/tests/ui/sanitizer/cfi-coroutine.rs b/tests/ui/sanitizer/cfi-coroutine.rs
new file mode 100644
index 00000000000..5c6a489a7e8
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-coroutine.rs
@@ -0,0 +1,67 @@
+// Verifies that we can call dynamic coroutines
+
+//@ revisions: cfi kcfi
+// FIXME(#122848) Remove only-linux once OSX CFI binaries work
+//@ only-linux
+//@ edition: 2024
+//@ [cfi] needs-sanitizer-cfi
+//@ [kcfi] needs-sanitizer-kcfi
+//@ compile-flags: -C target-feature=-crt-static
+//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
+//@ [cfi] compile-flags: -Z sanitizer=cfi
+//@ [kcfi] compile-flags: -Z sanitizer=kcfi
+//@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off
+//@ compile-flags: --test -Z unstable-options
+//@ run-pass
+
+#![feature(coroutines)]
+#![feature(coroutine_trait)]
+#![feature(noop_waker)]
+#![feature(gen_blocks)]
+#![feature(async_iterator)]
+
+use std::ops::{Coroutine, CoroutineState};
+use std::pin::{pin, Pin};
+use std::task::{Context, Poll, Waker};
+use std::async_iter::AsyncIterator;
+
+#[test]
+fn general_coroutine() {
+    let mut coro = |x: i32| {
+        yield x;
+        "done"
+    };
+    let mut abstract_coro: Pin<&mut dyn Coroutine<i32,Yield=i32,Return=&'static str>> = pin!(coro);
+    assert_eq!(abstract_coro.as_mut().resume(2), CoroutineState::Yielded(2));
+    assert_eq!(abstract_coro.as_mut().resume(0), CoroutineState::Complete("done"));
+}
+
+async fn async_fn() {}
+
+#[test]
+fn async_coroutine() {
+    let f: fn() -> Pin<Box<dyn Future<Output = ()>>> = || Box::pin(async_fn());
+    let _ = async { f().await; };
+    assert_eq!(f().as_mut().poll(&mut Context::from_waker(Waker::noop())), Poll::Ready(()));
+}
+
+async gen fn async_gen_fn() -> u8 {
+    yield 5;
+}
+
+#[test]
+fn async_gen_coroutine() {
+    let f: fn() -> Pin<Box<dyn AsyncIterator<Item = u8>>> = || Box::pin(async_gen_fn());
+    assert_eq!(f().as_mut().poll_next(&mut Context::from_waker(Waker::noop())),
+               Poll::Ready(Some(5)));
+}
+
+gen fn gen_fn() -> u8 {
+    yield 6;
+}
+
+#[test]
+fn gen_coroutine() {
+    let f: fn() -> Box<dyn Iterator<Item = u8>> = || Box::new(gen_fn());
+    assert_eq!(f().next(), Some(6));
+}
diff --git a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs
index 273b8785fae..8f79de11748 100644
--- a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs
+++ b/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs
@@ -1,11 +1,41 @@
 // Verifies that casting a method to a function pointer works.
-//
-// FIXME(#122848): Remove only-linux when fixed.
+
+//@ revisions: cfi kcfi
+// FIXME(#122848) Remove only-linux once OSX CFI binaries work
 //@ only-linux
-//@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ [cfi] needs-sanitizer-cfi
+//@ [kcfi] needs-sanitizer-kcfi
+//@ compile-flags: -C target-feature=-crt-static
+//@ [cfi] compile-flags: -C opt-level=0 -C codegen-units=1 -C lto
+//@ [cfi] compile-flags: -C prefer-dynamic=off
+//@ [cfi] compile-flags: -Z sanitizer=cfi
+//@ [kcfi] compile-flags: -Z sanitizer=kcfi
+//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
 //@ run-pass
 
+trait Foo {
+    fn foo(&self);
+    fn bar(&self);
+}
+
+struct S;
+
+impl Foo for S {
+    fn foo(&self) {}
+    #[track_caller]
+    fn bar(&self) {}
+}
+
+struct S2 {
+    f: fn(&S)
+}
+
+impl S2 {
+    fn foo(&self, s: &S) {
+        (self.f)(s)
+    }
+}
+
 trait Trait1 {
     fn foo(&self);
 }
@@ -20,4 +50,8 @@ fn main() {
     let type1 = Type1 {};
     let f = <Type1 as Trait1>::foo;
     f(&type1);
+    // Check again with different optimization barriers
+    S2 { f: <S as Foo>::foo }.foo(&S);
+    // Check mismatched #[track_caller]
+    S2 { f: <S as Foo>::bar }.foo(&S)
 }
diff --git a/tests/ui/sanitizer/cfi-self-ref.rs b/tests/ui/sanitizer/cfi-self-ref.rs
index f8793aec6e2..3b524ac661c 100644
--- a/tests/ui/sanitizer/cfi-self-ref.rs
+++ b/tests/ui/sanitizer/cfi-self-ref.rs
@@ -9,6 +9,7 @@
 //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
+//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
 //@ run-pass
 
 use std::marker::PhantomData;
diff --git a/tests/ui/sanitizer/cfi-supertraits.rs b/tests/ui/sanitizer/cfi-supertraits.rs
new file mode 100644
index 00000000000..ed3d722ebb7
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-supertraits.rs
@@ -0,0 +1,73 @@
+#![feature(trait_upcasting)]
+// Check that super-traits are callable.
+
+//@ revisions: cfi kcfi
+// FIXME(#122848) Remove only-linux once OSX CFI binaries work
+//@ only-linux
+//@ [cfi] needs-sanitizer-cfi
+//@ [kcfi] needs-sanitizer-kcfi
+//@ compile-flags: -C target-feature=-crt-static
+//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
+//@ [cfi] compile-flags: -Z sanitizer=cfi
+//@ [kcfi] compile-flags: -Z sanitizer=kcfi
+//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
+//@ run-pass
+
+trait Parent1 {
+    type P1;
+    fn p1(&self) -> Self::P1;
+}
+
+trait Parent2 {
+    type P2;
+    fn p2(&self) -> Self::P2;
+}
+
+trait Child : Parent1 + Parent2 {
+    type C;
+    fn c(&self) -> Self::C;
+}
+
+struct Foo;
+
+impl Parent1 for Foo {
+    type P1 = u16;
+    fn p1(&self) -> Self::P1 {
+        println!("p1");
+        1
+    }
+}
+
+impl Parent2 for Foo {
+    type P2 = u32;
+    fn p2(&self) -> Self::P2 {
+        println!("p2");
+        2
+    }
+}
+
+impl Child for Foo {
+    type C = u8;
+    fn c(&self) -> Self::C {
+        println!("c");
+        0
+    }
+}
+
+fn main() {
+    // Child can access its own methods and super methods.
+    let x = &Foo as &dyn Child<C=u8,P1=u16,P2=u32>;
+    x.c();
+    x.p1();
+    x.p2();
+    // Parents can be created and access their methods.
+    let y = &Foo as &dyn Parent1<P1=u16>;
+    y.p1();
+    let z = &Foo as &dyn Parent2<P2=u32>;
+    z.p2();
+    // Trait upcasting works
+    let x1 = x as &dyn Parent1<P1=u16>;
+    x1.p1();
+    let x2 = x as &dyn Parent2<P2=u32>;
+    x2.p2();
+}
diff --git a/tests/ui/sanitizer/cfi-virtual-auto.rs b/tests/ui/sanitizer/cfi-virtual-auto.rs
index 517c3d49f76..6971d516a20 100644
--- a/tests/ui/sanitizer/cfi-virtual-auto.rs
+++ b/tests/ui/sanitizer/cfi-virtual-auto.rs
@@ -9,6 +9,7 @@
 //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
+//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
 //@ run-pass
 
 trait Foo {
diff --git a/tests/ui/simd/intrinsic/ptr-cast.rs b/tests/ui/simd/intrinsic/ptr-cast.rs
index 83d86baf334..0490734b48a 100644
--- a/tests/ui/simd/intrinsic/ptr-cast.rs
+++ b/tests/ui/simd/intrinsic/ptr-cast.rs
@@ -4,8 +4,8 @@
 
 extern "rust-intrinsic" {
     fn simd_cast_ptr<T, U>(x: T) -> U;
-    fn simd_expose_addr<T, U>(x: T) -> U;
-    fn simd_from_exposed_addr<T, U>(x: T) -> U;
+    fn simd_expose_provenance<T, U>(x: T) -> U;
+    fn simd_with_exposed_provenance<T, U>(x: T) -> U;
 }
 
 #[derive(Copy, Clone)]
@@ -22,12 +22,12 @@ fn main() {
         // change constness and type
         let const_ptrs: V<*const u8> = simd_cast_ptr(ptrs);
 
-        let exposed_addr: V<usize> = simd_expose_addr(const_ptrs);
+        let exposed_addr: V<usize> = simd_expose_provenance(const_ptrs);
 
-        let from_exposed_addr: V<*mut i8> = simd_from_exposed_addr(exposed_addr);
+        let with_exposed_provenance: V<*mut i8> = simd_with_exposed_provenance(exposed_addr);
 
         assert!(const_ptrs.0 == [ptr as *const u8, core::ptr::null()]);
         assert!(exposed_addr.0 == [ptr as usize, 0]);
-        assert!(from_exposed_addr.0 == ptrs.0);
+        assert!(with_exposed_provenance.0 == ptrs.0);
     }
 }
diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs
new file mode 100644
index 00000000000..5c96c653df5
--- /dev/null
+++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
+//~^ ERROR expected a pattern, found an expression
+//~| ERROR cannot find type `T` in this scope
+//~| ERROR const and type arguments are not allowed on builtin type `str`
+//~| ERROR expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes`
+}
diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
new file mode 100644
index 00000000000..d62c019a1e1
--- /dev/null
+++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
@@ -0,0 +1,36 @@
+error: expected a pattern, found an expression
+  --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:31
+   |
+LL |     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
+   |                               ^^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:55
+   |
+LL |     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
+   |                                                       ^ not found in this scope
+
+error[E0109]: const and type arguments are not allowed on builtin type `str`
+  --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:15
+   |
+LL |     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
+   |         ---   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^ const and type arguments not allowed
+   |         |
+   |         not allowed on builtin type `str`
+   |
+help: primitive type `str` doesn't have generic parameters
+   |
+LL -     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
+LL +     let str::as_bytes;
+   |
+
+error[E0533]: expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes`
+  --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:9
+   |
+LL |     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constant
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0109, E0412, E0533.
+For more information about an error, try `rustc --explain E0109`.
diff --git a/tests/ui/specialization/issue-39448.rs b/tests/ui/specialization/issue-39448.rs
index a15c4bd6b7f..1c8843d983a 100644
--- a/tests/ui/specialization/issue-39448.rs
+++ b/tests/ui/specialization/issue-39448.rs
@@ -22,6 +22,7 @@ trait FromA<T> {
 }
 
 impl<T: A, U: A + FromA<T>> FromA<T> for U {
+    //~^ ERROR cycle detected when computing whether impls specialize one another
     default fn from(x: T) -> Self {
         ToA::to(x)
     }
@@ -42,7 +43,7 @@ where
 
 #[allow(dead_code)]
 fn foo<T: A, U: A>(x: T, y: U) -> U {
-    x.foo(y.to()).to() //~ ERROR overflow evaluating the requirement
+    x.foo(y.to()).to()
 }
 
 fn main() {
diff --git a/tests/ui/specialization/issue-39448.stderr b/tests/ui/specialization/issue-39448.stderr
index dc5db4f4285..e2c5f8c4846 100644
--- a/tests/ui/specialization/issue-39448.stderr
+++ b/tests/ui/specialization/issue-39448.stderr
@@ -8,28 +8,21 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0275]: overflow evaluating the requirement `T: FromA<U>`
-  --> $DIR/issue-39448.rs:45:13
-   |
-LL |     x.foo(y.to()).to()
-   |             ^^
-   |
-note: required for `T` to implement `FromA<U>`
-  --> $DIR/issue-39448.rs:24:29
+error[E0391]: cycle detected when computing whether impls specialize one another
+  --> $DIR/issue-39448.rs:24:1
    |
 LL | impl<T: A, U: A + FromA<T>> FromA<T> for U {
-   |                   --------  ^^^^^^^^     ^
-   |                   |
-   |                   unsatisfied trait bound introduced here
-note: required for `U` to implement `ToA<T>`
-  --> $DIR/issue-39448.rs:34:12
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: ...which requires evaluating trait selection obligation `u16: FromA<u8>`...
+   = note: ...which again requires computing whether impls specialize one another, completing the cycle
+note: cycle used when building specialization graph of trait `FromA`
+  --> $DIR/issue-39448.rs:20:1
    |
-LL | impl<T, U> ToA<U> for T
-   |            ^^^^^^     ^
-LL | where
-LL |     U: FromA<T>,
-   |        -------- unsatisfied trait bound introduced here
+LL | trait FromA<T> {
+   | ^^^^^^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error: aborting due to 1 previous error; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0275`.
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/specialization/issue-39618.rs b/tests/ui/specialization/issue-39618.rs
index 5b9b012e665..14a6fcf572e 100644
--- a/tests/ui/specialization/issue-39618.rs
+++ b/tests/ui/specialization/issue-39618.rs
@@ -2,8 +2,6 @@
 // FIXME(JohnTitor): Centril pointed out this looks suspicions, we should revisit here.
 // More context: https://github.com/rust-lang/rust/pull/69192#discussion_r379846796
 
-//@ check-pass
-
 #![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo {
@@ -19,6 +17,7 @@ impl<T> Bar for T where T: Foo {
 }
 
 impl<T> Foo for T where T: Bar {
+    //~^ ERROR cycle detected when computing whether impls specialize one another
     fn foo(&self) {}
 }
 
diff --git a/tests/ui/specialization/issue-39618.stderr b/tests/ui/specialization/issue-39618.stderr
index 19de60c7c17..756162ce92c 100644
--- a/tests/ui/specialization/issue-39618.stderr
+++ b/tests/ui/specialization/issue-39618.stderr
@@ -1,5 +1,5 @@
 warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-39618.rs:7:12
+  --> $DIR/issue-39618.rs:5:12
    |
 LL | #![feature(specialization)]
    |            ^^^^^^^^^^^^^^
@@ -8,5 +8,21 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
-warning: 1 warning emitted
+error[E0391]: cycle detected when computing whether impls specialize one another
+  --> $DIR/issue-39618.rs:19:1
+   |
+LL | impl<T> Foo for T where T: Bar {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: ...which requires evaluating trait selection obligation `u64: Bar`...
+   = note: ...which again requires computing whether impls specialize one another, completing the cycle
+note: cycle used when building specialization graph of trait `Foo`
+  --> $DIR/issue-39618.rs:7:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error: aborting due to 1 previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/stability-attribute/stability-in-private-module.rs b/tests/ui/stability-attribute/stability-in-private-module.rs
index f12e9198b0d..df94931690b 100644
--- a/tests/ui/stability-attribute/stability-in-private-module.rs
+++ b/tests/ui/stability-attribute/stability-in-private-module.rs
@@ -1,4 +1,4 @@
 fn main() {
-    let _ = std::thread::thread_info::current_thread();
-    //~^ERROR module `thread_info` is private
+    let _ = std::sys::os::errno();
+    //~^ERROR module `sys` is private
 }
diff --git a/tests/ui/stability-attribute/stability-in-private-module.stderr b/tests/ui/stability-attribute/stability-in-private-module.stderr
index 9eb4d3efc8b..e65f8aa9b1f 100644
--- a/tests/ui/stability-attribute/stability-in-private-module.stderr
+++ b/tests/ui/stability-attribute/stability-in-private-module.stderr
@@ -1,13 +1,13 @@
-error[E0603]: module `thread_info` is private
-  --> $DIR/stability-in-private-module.rs:2:26
+error[E0603]: module `sys` is private
+  --> $DIR/stability-in-private-module.rs:2:18
    |
-LL |     let _ = std::thread::thread_info::current_thread();
-   |                          ^^^^^^^^^^^  -------------- function `current_thread` is not publicly re-exported
-   |                          |
-   |                          private module
+LL |     let _ = std::sys::os::errno();
+   |                  ^^^      ----- function `errno` is not publicly re-exported
+   |                  |
+   |                  private module
    |
-note: the module `thread_info` is defined here
-  --> $SRC_DIR/std/src/thread/mod.rs:LL:COL
+note: the module `sys` is defined here
+  --> $SRC_DIR/std/src/lib.rs:LL:COL
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-1660.rs b/tests/ui/static/issue-1660.rs
index a114a908313..a114a908313 100644
--- a/tests/ui/issues/issue-1660.rs
+++ b/tests/ui/static/issue-1660.rs
diff --git a/tests/ui/statics/nested-allocations-dont-inherit-codegen-attrs.rs b/tests/ui/statics/nested-allocations-dont-inherit-codegen-attrs.rs
new file mode 100644
index 00000000000..0b7e659c7b7
--- /dev/null
+++ b/tests/ui/statics/nested-allocations-dont-inherit-codegen-attrs.rs
@@ -0,0 +1,11 @@
+//@ build-pass
+
+// Make sure that the nested static allocation for `FOO` doesn't inherit `no_mangle`.
+#[no_mangle]
+pub static mut FOO: &mut [i32] = &mut [42];
+
+// Make sure that the nested static allocation for `BAR` doesn't inherit `export_name`.
+#[export_name = "BAR_"]
+pub static mut BAR: &mut [i32] = &mut [42];
+
+fn main() {}
diff --git a/tests/ui/statics/nested_thread_local.rs b/tests/ui/statics/nested_thread_local.rs
new file mode 100644
index 00000000000..a512016335a
--- /dev/null
+++ b/tests/ui/statics/nested_thread_local.rs
@@ -0,0 +1,14 @@
+// Check that we forbid nested statics in `thread_local` statics.
+
+#![feature(const_refs_to_cell)]
+#![feature(thread_local)]
+
+#[thread_local]
+static mut FOO: &u32 = {
+    //~^ ERROR: does not support implicit nested statics
+    // Prevent promotion (that would trigger on `&42` as an expression)
+    let x = 42;
+    &{ x }
+};
+
+fn main() {}
diff --git a/tests/ui/statics/nested_thread_local.stderr b/tests/ui/statics/nested_thread_local.stderr
new file mode 100644
index 00000000000..30c742626fa
--- /dev/null
+++ b/tests/ui/statics/nested_thread_local.stderr
@@ -0,0 +1,8 @@
+error: #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead
+  --> $DIR/nested_thread_local.rs:7:1
+   |
+LL | static mut FOO: &u32 = {
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs
index 66f663ce077..50491d5ef3e 100644
--- a/tests/ui/structs-enums/type-sizes.rs
+++ b/tests/ui/structs-enums/type-sizes.rs
@@ -4,7 +4,7 @@
 #![allow(dead_code)]
 #![feature(generic_nonzero)]
 #![feature(never_type)]
-#![feature(pointer_is_aligned)]
+#![feature(pointer_is_aligned_to)]
 #![feature(strict_provenance)]
 
 use std::mem::size_of;
diff --git a/tests/ui/traits/stack-error-order-dependence-2.rs b/tests/ui/traits/stack-error-order-dependence-2.rs
new file mode 100644
index 00000000000..323685aa15b
--- /dev/null
+++ b/tests/ui/traits/stack-error-order-dependence-2.rs
@@ -0,0 +1,24 @@
+//@ check-pass
+// Regression test for <https://github.com/rust-lang/rust/issues/123303>.
+// This time EXCEPT without `dyn` builtin bounds :^)
+
+pub trait Trait: Supertrait {}
+
+trait Impossible {}
+impl<F: ?Sized + Impossible> Trait for F {}
+
+pub trait Supertrait {}
+
+impl<T: ?Sized + Trait + Impossible> Supertrait for T {}
+
+fn needs_supertrait<T: ?Sized + Supertrait>() {}
+fn needs_trait<T: ?Sized + Trait>() {}
+
+struct A;
+impl Trait for A where A: Supertrait {}
+impl Supertrait for A {}
+
+fn main() {
+    needs_supertrait::<A>();
+    needs_trait::<A>();
+}
diff --git a/tests/ui/traits/stack-error-order-dependence.rs b/tests/ui/traits/stack-error-order-dependence.rs
new file mode 100644
index 00000000000..037c292a542
--- /dev/null
+++ b/tests/ui/traits/stack-error-order-dependence.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+// Regression test for <https://github.com/rust-lang/rust/issues/123303>.
+
+pub trait Trait: Supertrait {}
+
+trait Impossible {}
+impl<F: ?Sized + Impossible> Trait for F {}
+
+pub trait Supertrait {}
+
+impl<T: ?Sized + Trait + Impossible> Supertrait for T {}
+
+fn needs_supertrait<T: ?Sized + Supertrait>() {}
+fn needs_trait<T: ?Sized + Trait>() {}
+
+fn main() {
+    needs_supertrait::<dyn Trait>();
+    needs_trait::<dyn Trait>();
+}
diff --git a/tests/ui/unpretty/hir-tree.rs b/tests/ui/unpretty/hir-tree.rs
new file mode 100644
index 00000000000..3388c60c425
--- /dev/null
+++ b/tests/ui/unpretty/hir-tree.rs
@@ -0,0 +1,10 @@
+//@ build-pass
+//@ compile-flags: -o - -Zunpretty=hir-tree
+//@ check-stdout
+//@ dont-check-compiler-stdout
+//@ dont-check-compiler-stderr
+//@ regex-error-pattern: Hello, Rustaceans!
+
+fn main() {
+    println!("Hello, Rustaceans!");
+}
diff --git a/tests/ui/wf/wf-fn-def-check-sig-1.rs b/tests/ui/wf/wf-fn-def-check-sig-1.rs
new file mode 100644
index 00000000000..6d9e1f38f8d
--- /dev/null
+++ b/tests/ui/wf/wf-fn-def-check-sig-1.rs
@@ -0,0 +1,44 @@
+// Regression test for #84533.
+
+use std::marker::PhantomData;
+
+fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> {
+    PhantomData
+}
+
+fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
+    let f = foo::<'b, 'a>;
+    f.baz(x)
+    //~^ ERROR lifetime may not live long enough
+}
+
+trait Foo<'a, 'b, T: ?Sized> {
+    fn baz(self, s: &'a T) -> &'b T;
+}
+impl<'a, 'b, R, F, T: ?Sized> Foo<'a, 'b, T> for F
+where
+    F: Fn() -> R,
+    R: ProofForConversion<'a, 'b, T>,
+{
+    fn baz(self, s: &'a T) -> &'b T {
+        self().convert(s)
+    }
+}
+
+trait ProofForConversion<'a, 'b, T: ?Sized> {
+    fn convert(self, s: &'a T) -> &'b T;
+}
+impl<'a, 'b, T: ?Sized> ProofForConversion<'a, 'b, T> for PhantomData<&'b &'a ()> {
+    fn convert(self, s: &'a T) -> &'b T {
+        s
+    }
+}
+
+fn main() {
+    let d;
+    {
+        let x = "Hello World".to_string();
+        d = extend_lifetime(&x);
+    }
+    println!("{}", d);
+}
diff --git a/tests/ui/wf/wf-fn-def-check-sig-1.stderr b/tests/ui/wf/wf-fn-def-check-sig-1.stderr
new file mode 100644
index 00000000000..a93449ad3c6
--- /dev/null
+++ b/tests/ui/wf/wf-fn-def-check-sig-1.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/wf-fn-def-check-sig-1.rs:11:5
+   |
+LL | fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
+   |                    --  -- lifetime `'b` defined here
+   |                    |
+   |                    lifetime `'a` defined here
+LL |     let f = foo::<'b, 'a>;
+LL |     f.baz(x)
+   |     ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/wf/wf-fn-def-check-sig-2.rs b/tests/ui/wf/wf-fn-def-check-sig-2.rs
new file mode 100644
index 00000000000..51740dca8e9
--- /dev/null
+++ b/tests/ui/wf/wf-fn-def-check-sig-2.rs
@@ -0,0 +1,44 @@
+// Regression test for #84533 involving higher-ranked regions
+// in the return type.
+use std::marker::PhantomData;
+
+fn foo<'c, 'b, 'a>(_: &'c ()) -> (&'c (), PhantomData<&'b &'a ()>) {
+    (&(), PhantomData)
+}
+
+fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
+    let f = foo;
+    f.baz(x)
+    //~^ ERROR lifetime may not live long enough
+}
+
+trait Foo<'a, 'b, T: ?Sized> {
+    fn baz(self, s: &'a T) -> &'b T;
+}
+impl<'a, 'b, R, F, T: ?Sized> Foo<'a, 'b, T> for F
+where
+    F: for<'c> Fn(&'c ()) -> (&'c (), R),
+    R: ProofForConversion<'a, 'b, T>,
+{
+    fn baz(self, s: &'a T) -> &'b T {
+        self(&()).1.convert(s)
+    }
+}
+
+trait ProofForConversion<'a, 'b, T: ?Sized> {
+    fn convert(self, s: &'a T) -> &'b T;
+}
+impl<'a, 'b, T: ?Sized> ProofForConversion<'a, 'b, T> for PhantomData<&'b &'a ()> {
+    fn convert(self, s: &'a T) -> &'b T {
+        s
+    }
+}
+
+fn main() {
+    let d;
+    {
+        let x = "Hello World".to_string();
+        d = extend_lifetime(&x);
+    }
+    println!("{}", d);
+}
diff --git a/tests/ui/wf/wf-fn-def-check-sig-2.stderr b/tests/ui/wf/wf-fn-def-check-sig-2.stderr
new file mode 100644
index 00000000000..404d3cc4513
--- /dev/null
+++ b/tests/ui/wf/wf-fn-def-check-sig-2.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/wf-fn-def-check-sig-2.rs:11:5
+   |
+LL | fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
+   |                    --  -- lifetime `'b` defined here
+   |                    |
+   |                    lifetime `'a` defined here
+LL |     let f = foo;
+LL |     f.baz(x)
+   |     ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to 1 previous error
+
diff --git a/triagebot.toml b/triagebot.toml
index 0df71c60d54..55f0d32398f 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -788,6 +788,7 @@ compiler-team-contributors = [
     "@Nadrieril",
     "@fmease",
     "@fee1-dead",
+    "@BoxyUwU",
 ]
 compiler = [
     "compiler-team",